packages feed

haskeem-0.7.4: macro-test.scm

(write-string "################ numeric-if test\n")

; This tests how many times everything gets evaluated
(define probe 0)

(define neg-action (lambda () (set! probe (+ probe 1)) "negative!"))
(define zero-action (lambda () (set! probe (+ probe 10)) "zero!"))
(define pos-action (lambda () (set! probe (+ probe 100)) "positive!"))

; The value returned from this determines which of the three branches is chosen
(define test-value (lambda () (set! probe (+ probe 1000)) 1))

; This version is careful to evaluate tval only once
(defmacro (numeric-if-1 tval ifn ifz ifp)
  (let ((nit (new-symbol)))
    `(let ((,nit ,tval))
       (if (number? ,nit)
	   (if (negative? ,nit)
	       ,ifn
	       (if (positive? ,nit)
		   ,ifp
		   ,ifz))
	   (raise "error: non-numeric test value passed to numeric-if")))))

; This version might evaluate tval two or three times
(defmacro (numeric-if-2 tval ifn ifz ifp)
  `(if (number? ,tval)
       (if (negative? ,tval)
	   ,ifn
	   (if (positive? ,tval)
	       ,ifp
	       ,ifz))
       (raise "error: non-numeric test value passed to numeric-if")))

; A function version of numeric-if would evaluate each argument precisely once,
; so that after the test the value of probe would be 1111

(write-string "test-value returns ")
(display (test-value))
(newline)
(set! probe 0)
(write-string "before: probe is " (number->string probe) #\newline)
(define ret
  (guard
   (err ((begin (write-string "exception is '")
		(display err)
		(write-string "'\n")
		#t) err))
   (numeric-if-1 (test-value)
		 (neg-action)
		 (zero-action)
		 (pos-action))))
(write-string "after:  probe is " (number->string probe) #\newline)
(write-string "result is ")
(display ret)
(newline)

(write-string "################ assertion test\n")
; really we ought to raise an exception here if the assertion failed;
; this is just to be friendly for the test
(defmacro (assert some-cond)
  `(when (not ,some-cond)
	 (write-string "assertion failure: ")
	 (display ',some-cond)
	 (newline)))

(define x "foo")
(display x)
(newline)
(assert (eqv? x "bar"))

(write-string "################ while test\n")
(defmacro (while some-cond . some-actions)
  (let ((mc (new-symbol)))
    `(do ((,mc 0 (+ ,mc 1)))
	 ((not ,some-cond) ,mc)
       ,@some-actions)))

(define i 0)
(define count (while (< i 10) (set! i (+ i 1)) (display i)))
(write-string #\newline "i sez " (number->string i) #\newline
	      "loop count sez " (number->string count) #\newline)

(write-string "######## nested while test\n")
(define j 0)
(set! i 0)
(while (< i 4)
       (set! j 0)
       (while (< j 4)
	      (set! j (+ j 1))
	      (write-string (number->string i) "/"
			    (number->string j) #\newline))
       (set! i (+ i 1)))

(write-string "################ swap test\n")
(defmacro (swap var1 var2)
  (let ((vs (new-symbol)))
    `(let ((,vs ,var1))
       (set! ,var1 ,var2)
       (set! ,var2 ,vs))))

(define val1 0)
(define val2 1)
(write-string "before: val1 is " (number->string val1)
	      ", val2 is " (number->string val2) #\newline)
(swap val1 val2)
(write-string "after:  val1 is " (number->string val1)
	      ", val2 is " (number->string val2) #\newline)

; can we break it? I don't think so... at least not this way:
; haskeem doesn't support re-binding of special forms, and set! is one
(write-string "before: val1 is " (number->string val1)
	      ", val2 is " (number->string val2) #\newline)
(let ((set! display))
  (swap val1 val2))
(write-string "after:  val1 is " (number->string val1)
	      ", val2 is " (number->string val2) #\newline)

(write-string "################ th-th-that's all, folks!\n")