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))