Note: This is a class activity, nothing needs to be delivered.
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
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))