You are here:   ArielOrtiz.com > Programming Languages > Macros

Macros

Objectives

During this activity, students should be able to:

This activity helps the student develop the following skills, values and attitudes: ability to analyze and synthesize, capacity for identifying and solving problems, and efficient use of computer systems.

Activity Description

Individually, solve the following set of meta-programming exercises using Clojure macros.

Place all your functions in a name space called macros.

  1. This is the documentation for Clojure's or macro:

    or
    macro

    Usage:

    (or)
    (or x)
    (or x & next)

    Evaluates its expressions one at a time, from left to right. If a form returns a logical true value, it returns that value and doesn't evaluate any of the other expressions, otherwise it returns the value of the last expression. (or) returns nil.

    Write a macro called my-or that works as described above. Make sure that any expression gets evaluated at most once. You may not use Clojure's or macro. Usage examples:

    (macros/my-or)                                   ⇒ nil
    (macros/my-or false :one nil :two false :three)  ⇒ :one
    (macros/my-or false false nil)                   ⇒ nil
    (macros/my-or nil nil false)                     ⇒ false
    
  2. Write a macro called do-loop that implements a post-test loop control statement. It must combine the functionality of C's do-while statement and Pascal's repeat-until statement.

    This construct consists of a body (one or more expressions, presumably with side effects) and a final conditional form prefaced with a :while or :until keyword. First, the expressions in the body are evaluated sequentially, and then the condition is evaluated. If the final form uses a :while keyword, the body of the loop is repeated while the condition holds true. On the other hand, if the final form uses an :until keyword, the body of the loop is repeated while the condition holds false (or in other words, the loop terminates when the condition is true). Returns nil.

    Here are some examples:

    (def i (atom 0))
    (macros/do-loop
      (println @i)
      (swap! i inc)
      (:until (= @i 5)))
        ;;; prints:
        ;;; 0
        ;;; 1
        ;;; 2
        ;;; 3
        ;;; 4
        ⇒ nil
        
    (def j (atom 1))
    (macros/do-loop
      (println @j)
      (swap! j inc)
      (:while (<= @j 5)))
        ;;; prints:    
        ;;; 1
        ;;; 2
        ;;; 3
        ;;; 4
        ;;; 5
        ⇒ nil
  3. Write a macro called do-reverse. It should work like the ordinary do special form, but evaluating its expressions in reverse order. This macro should always return nil.

    Examples:

    (do-reverse) ⇒ nil
         
    (do-reverse (println "one") (println "two") (println "three"))
      ;;; prints:    
      ;;; three
      ;;; two
      ;;; one
      ⇒ nil
        
    (do-reverse (do (println "a") (* 6 7)) (println "b"))
      ;;; prints:    
      ;;; b
      ;;; a  
      ⇒ nil
    
  4. Write a macro called def-pred, that takes a name, an arg vector, and a body of one or more expressions. The macro should define two predicate functions: a regular one and its negated version. The name of the negated predicate should be the same as name but with a "not-" prefix, and its result should be negated using the not function (see the test code for an example).

    Examples:

    (macroexpand-1 '(def-pred less-than-one? [x] (< x 1)))
      ⇒(do (clojure.core/defn less-than-one? [x] (< x 1)) 
           (clojure.core/defn not-less-than-one? [x] (clojure.core/not (do (< x 1)))))
           
    (def-pred less-than-one? [x] (< x 1))
    
    (less-than-one? 0)
      ⇒ true
      
    (less-than-one? 2)
      ⇒ false
      
    (not-less-than-one? 0)
      ⇒ false
      
    (not-less-than-one? 2)
      ⇒ true
    
    (macroexpand-1 '(def-pred plural? [s] (println "check s in" s) (= \s (last s)))))
      ⇒ (do (clojure.core/defn plural? [s] (println "check s in" s) (= \s (last s)))
            (clojure.core/defn not-plural? [s] (clojure.core/not (do (println "check s in" s) 
                                                                     (= \s (last s))))))
    
    (def-pred plural? [s] (println "check s in" s) (= \s (last s)))
    
    (plural? "boys")
      ;;; prints:    
      ;;; check s in boys
      ⇒ true
      
    (plural? "girl")
      ;;; prints:    
      ;;; check s in girl
      ⇒ false
      
    (not-plural? "boys")
      ;;; prints:    
      ;;; check s in boys
      ⇒ false
      
    (not-plural? "girl")
      ;;; prints:    
      ;;; check s in girl
      ⇒ true
    

    NOTE: You will likely need to use the Clojure functions str and symbol when producing the negated predicate name.

Deliverables

Using the Online Assignment Delivery System (SETA), deliver the file called macros.clj containing your solutions. No assignments will be accepted through e-mail or any other means.

IMPORTANT: The program source file must include at the top the author's personal information (name and student id) within comments. For example:

   
;;; ITESM CEM, November 21, 2012.
;;; Clojure Source File
;;; Activity: Macros
;;; Author: Steve Rogers, 1166611

    .
    . (The rest of the program goes here)
    .

Due date: Wednesday, November 21.

Evaluation

This activity will be evaluated using the following criteria:

-10 The program doesn't contain within comments the author's personal information.
10 The program contains syntax errors.
DA The program was plagiarized.
10-100 Depending on the amount of exercises that were solved correctly.