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

# Macros Exercises

Note: This is a class activity, nothing needs to be delivered.

1. Write a Clojure macro called `debug`, that provides a simple debugging facility for Clojure code. When `(debug original-expression)` is evaluated, a debugging line should be printed to the standard output with the following format:

`debug:` original-expression `=>` evaluated-expression

Additionally, the `debug` macro should return the result of the evaluated expression. For example, the following code

`(inc (debug (* 4 5)))`

should return 21 and print this to the standard output:

`debug: (* 4 5) => 20`

Test your function with the following code:

```(defn fact
[n]
(if (zero? n)
1
(debug (* n (fact (dec n))))))

(println (fact 5))```

The expected output is:

```debug: (* n (fact (dec n))) => 1
debug: (* n (fact (dec n))) => 2
debug: (* n (fact (dec n))) => 6
debug: (* n (fact (dec n))) => 24
debug: (* n (fact (dec n))) => 120
120```
2. Write a Clojure macro called `IF` (note the uppercase letters). Its purpose is to provide a conditional statement that is syntactically a bit more similar to those found in languages like Pascal or Fortran. It has the following form:

(`IF` condition `:THEN` exp1 exp2`:ELSE` exp3 exp4 …)

It should basically expand to the following conventional Clojure `if` form:

(`if` condition (`do` exp1 exp2 …) (`do` exp3 exp4 …))

Almost everything is optional in the `IF` macro, except condition. Also, the `:ELSE` keyword may come before the `:THEN` keyword. The following examples show some legal forms and their results:

```user=> (IF (> 3 1) :THEN 'ok :ELSE 'oops)
ok
user=> (IF (> 3 1) :THEN 'ok)
ok
user=> (IF (< 3 1) :ELSE 'ok)
ok
user=> (IF (> 3 1) :ELSE 'oops)
nil
user=> (IF (> 3 1) :THEN)
nil
user=> (IF (> 3 1))
nil
user=> (macroexpand-1 '(IF (> 3 1)
:ELSE (println "Else section.") 'oops
:THEN (println "Then section.") 'ok))
(if (> 3 1) (do (println "Then section.") (quote ok))
(do (println "Else section.") (quote oops)))
user=> (macroexpand-1 '(IF (< 3 1) :ELSE 'ok))
(if (< 3 1) (do) (do (quote ok)))```

Any expression in-between condition and the first occurrence of the `:THEN` or `:ELSE` keywords should just be ignored:

```user=> (macroexpand-1 '(IF (< 3 1) 1 2 3 :THEN 4 5 6 :ELSE 7 8 9))
(if (< 3 1) (do 4 5 6) (do 7 8 9))```