#lang racket ; when does a term get evaluated? (define X 2) (define Y 3) ; if the world was purely functional it wouldn't matter if both parts ; of an 'if' were evaluated beforehand. Although it could be quite costly ; since you are doing unnecessary work that is just thrown away. (if (< X Y) (+ X X) (* Y Y) ) ; but if there are side effects it does matter (list (< X Y) (print "true") (print "false") ) ; so 'if' is clearly a different kind of operation than, say, 'list' (if (< X Y) (print "true") (print "false") ) ; note that the and and or operations are lazy, so an if ; (if condition consequent alternate) ; can also be written as this: ; (or (and condition consequent) alternate) (or (and (< X Y) (+ X X) ) (* Y Y) ) (or (and (< X Y) (print "true") ) (print "false") ) ; if we have and/or we could define our own if functon using ; the above relationship. ; But the arguments to our new function get evaluated before the call (define my-if (lambda (condition consequent alternate) (or (and condition consequent ) alternate ) ) ) ; it doesn't matter here (my-if (< X Y) (+ X X) (* Y Y) ) ; but it does if there are side effects in an argument! (my-if (< X Y) (print "true") (print "false") ) ; so we have to defer the evaluation of arguments in an ; if by wrapping them in lambda, and then evaluating only ; the one selected by the condition. Note the ( ) around ; the consequent and alternate closures to force evaluation ; Note that the operations or/and must also be special forms ; so somewhere there must be a built in conditional special ; form that delays evaluation of its arguments. (define my-lazy-if (lambda (condition consequent-closure alternate-closure) (or (and condition (consequent-closure) ) (alternate-closure) ) ) ) ; it doesn't matter here (my-lazy-if (< X Y) (lambda () (+ X X)) (lambda () (* Y Y)) ) ; but it does if there are side effects in an argument! (my-lazy-if (< X Y) (lambda () (print "true")) (lambda () (print "false")) ) ; lambda wrapping to create lazy evaluation is somewhat annoying. (my-lazy-if (< X Y) (lambda () (my-lazy-if (> X Y) (lambda () "cc true") (lambda () "cc false"))) (lambda () "c false") ) ; that is why it is built in to the special forms like if, and, or ; using macros. ; we can also introduce special syntax that does the closure construction ; for us (define-syntax-rule (macro-if condition consequent alternate) ((lambda (consequent-closure alternate-closure) (or (and condition (consequent-closure) ) (alternate-closure) ) ) (lambda () consequent) (lambda () alternate) ) ) (macro-if #t (print 1) (print 0)) (define ifif (lambda (x) (macro-if (= x 0) (print "a") (macro-if (= x 1) (print "b") (print "c")))))