1
0
tiger-scheme/example.scm

509 lines
11 KiB
Scheme

;;; Standard lib, in scheme
; Lists
(define (foldl f i l)
(if (null? l)
i
(foldl f (f (car l) i) (cdr l))))
(define (foldr f i l)
(if (null? l)
i
(f (car l) (foldr f i (cdr l)))))
(define (map f l)
(if (null? l)
'()
(foldr (lambda (e a) (cons (f e) a)) '() l)))
(define (length l)
(foldl + 0 (map (lambda (x) 1) l)))
(define (reverse l)
(foldl cons '() l))
(define (append l1 l2)
(foldr cons l2 l1))
(define list-tail; Taken from https://people.csail.mit.edu/jaffer/r5rs/Pairs-and-lists.html
(lambda (x k)
(if (zero? k)
x
(list-tail (cdr x) (- k 1)))))
; Math
(define (= a b)
(if (<= a b)
(>= a b)
#f))
(define (zero? x) (= x 0))
(define (positive? x) (> x 0))
(define (negative? x) (< x 0))
(define (odd? x) (= (mod x 2) 1))
(define (even? x) (= (mod x 2) 0))
;;;;;;;; Testing stuff ;;;;;;;;;;
; Test some compilation stuff
(define f (lambda (x) ((lambda (y) (+ y 2)) (car x))))
(define g (lambda (x) (if ((lambda (y) (= y 2)) (car x))
y
'fuck)))
(define fac_fucked
( (lambda (f) (lambda (v) (f f v)))
(lambda (f v)
(if (= v 0)
1
(* v (f f (+ v -1)))))))
(display "Recursive combinator used on factorial.\n\tExpect: 120\n\tGotten: ")
(display (fac_fucked 5))
(newline)
; Test that function arguments are in correct order
(define (test-arg-order a b c)
(begin (display a)
(display " ")
(display b)
(display " ")
(display c)
(newline)))
(display "Testing that argument order is correct:\n\tExpect: 1 2 3\n\tGotten: ")
(test-arg-order 1 2 3)
(display "\n")
; Test string
(display "Hello World") (newline)
; Test functions
(define add-three (lambda (x y z) (+ (+ x z) y)))
; Test factorial
(define fac (lambda (x) (if (>= x 1) (* x (fac (+ x -1))) 1)))
(define (faca x a)
(if (>= x 1)
(faca (+ x -1) (* x a))
a))
(define x 5)
(display x) (newline)
(display (fac x)) (newline)
(display (faca x 1)) (newline)
; Test stuff?
(define (f . l) (cdr l))
(define y '(1 2 3))
(display y) (newline)
(display (car y)) (newline)
(display (cdr y)) (newline)
(display (append '(1 2 3) '(4 5 6))) (newline)
; Test system
(define (concat-string s sep)
(foldr (lambda (e a) (string-append (datum->string e) sep a))
""
s))
(define test
(lambda (name tests)
(begin (display name)
(display "\n\tExpect: ")
(display (concat-string (map car tests) " "))
(display "\n\tGotten: ")
(display (concat-string (map cdr tests) " "))
(newline))))
(define (header name) (display (string-append "\n * " name " *\n")))
(header "R5RS: Test equivalence")
(define (list-tail ls index)
(if (zero? index)
ls
(list-tail (cdr ls) (+ index -1))))
(define (list-ref ls index)
(car (list-tail ls index)))
; Actual Tests
(display "\n* R5RS: Quotation and quasi-quotation *\n")
(display "Testing quotation!\n\tExpect: (1 2 3)\n\tGotten: ")
(define (x) (quote (1 2 3)))
(display (x))
(newline)
(display "Testing quotation!\n\tExpect: (1 2 3)\n\tGotten: ")
(define (x) '(1 2 3))
(display (x))
(newline)
(display "Testing quasi-notation basics!\n\tExpect: (1 2 3)\n\tGotten: ")
(define (x) `(1 2 3))
(display (x))
(newline)
(display "Testing quasi-notation!\n\tExpect: (1 a 2 a 3 a 4)\n\tGotten: ")
(define (x p) `(1 ,p 2 ,p 3 ,p 4))
(display (x 'a))
(newline)
(display "Testing quasi-notation advanced!\n\tExpect: (1 2 3 4 5)\n\tGotten: ")
(define (x p) `(1 ,@p 3))
(display (x '(2 3 4)))
(newline)
(display "Testing quasi-notation advanced!\n\tExpect: (1 `(,a ,x 3) 4 5)\n\tGotten: ")
(define (f x y) `(,x `(,a ,x 3) 4 ,y))
(display (f 1 5))
(newline)
(display "Testing quasi-notation advanced!\n\tExpect: ((1 2) . 3)\n\tGotten: ")
(define (f) (cons `(1 2) 3))
(display (f))
(newline)
; Check set!
(set! x 10)
(display x) (newline)
(newline)
(display "* R5RS: Testing booleans *")
(newline)
(define fun-test
(lambda (name f cases)
(test (string-append "Testing function " name "")
(map (lambda (a) (cons (car a) (f (cdr a))))
cases))))
(fun-test "not" not
'( (#f . #t)
(#t . #f)
(#f . "hi")
(#f . 7)
(#f . a)
(#f . ())
))
(fun-test "boolean?" boolean?
'( (#t . #t)
(#t . #f)
(#f . "hi")
(#f . 7)
(#f . a)
(#f . ())
))
(header "R5RS: Testing numerical operators")
(fun-test "number?" number?
'( (#f . #t)
(#f . #f)
(#f . "hi")
(#t . 7)
(#t . 5232)
(#f . a)
(#f . ())
))
(header "R5RS: Testing fold and map")
(display "Testing sum over foldl!\n\tExpect: 28\n\tGotten: ")
(display (foldl + 0 '(1 2 3 4 5 6 7)))
(newline)
(display "Testing sum over foldr!\n\tExpect: 28\n\tGotten: ")
(display (foldr + 0 '(1 2 3 4 5 6 7)))
(newline)
(display "Testing map!\n\tExpect: (21 22 23)\n\tGotten: ")
(display (map (lambda (a) (+ 20 a)) '(1 2 3)))
(newline)
(display "Testing length!\n\tExpect: 13\n\tGotten: ")
(display (length '(1 2 3 1 2 3 1 2 3 1 2 3 1)))
(newline)
(display "Testing length!\n\tExpect: (5 4 3 2 1)\n\tGotten: ")
(display (reverse '(1 2 3 4 5)))
(newline)
(newline)
(display "* R5RS: Test string *")
(newline)
(display "Testing string-concat\n\tExpect: Hello World\n\tGotten: ")
(display (string-append "Hello" " " "World"))
(newline)
(define do-stuffer
(lambda (name_i arg1_i arg2_i)
(lambda (x)
(cons (list-ref x name_i)
(eqv? (list-ref x arg1_i)
(list-ref x arg2_i))))))
(define eqv-test
(lambda (name tests)
(test name (append (map (do-stuffer 0 1 2) tests)
(map (do-stuffer 0 2 1) tests)
))))
(eqv-test "eqv? booleans"
'(
(#t #t #t)
(#t #f #f)
(#f #t #f)
(#f #f #t)
))
(eqv-test "eqv? inter-types"
'(
(#f 2 a)
(#f 4 "Derp")
(#f () (a b))
(#f 9 ())
))
(eqv-test "eqv? symbols"
'(
(#t hello hello)
(#t World wOrld)
(#f hello world)
(#f hello World)
))
(header "R5RS: Test if-expressions")
(test "If expressions exp!"
`(
(6 . ,(* 3 (if #t 2 0)))
(0 . ,(* 3 (if #f 2 0)))
("Hello World" . ,(if #t "Hello World"))
("???" . ,(if #f "Hello World"))
))
(header "R5RS: Testing Eval system")
(display "Eval expression. Expect 6: ")
(display (eval '(* 2 (cdr '(2 . 3))) (scheme-report-environment 5)))
(newline)
(newline)
(display "* R5RS: Testing Macro system *")
(newline)
; Test define-syntax
(display "Test define-syntax:\n Expect: 4 ()\n Gotten: ")
(define-syntax const
(lambda (so)
`(lambda () ,(car (cdr so)))))
(define x (const 4))
(display (x))
(display " ")
(define x (const '()))
(display (x))
(display "\n")
(display "Test defining let using macroes:\n Expect: 23 82 105\n Gotten: ")
(define-syntax let
(lambda (vo)
`( (lambda ,(map car (cadr vo)) ,(caddr vo))
,@(map cadr (cadr vo)))))
(let ((a 23)
(b 82))
(begin (display a)
(display " ")
(display b)
(display " ")
(display (+ a b))))
(display "\n* R5RS: Lexical conventions *\n")
(define a-variable 20)
(if #f (begin
(display "Test case-insensitivity (required by R5RS)\n\tExpect: 20 20 20 20\n\tGotten: ")
(display a-variable) (display " ")
(display A-variable) (display " ")
(display a-VARiable) (display " ")
(display A-VARIABLE))
(display "Skipped test!\n"))
; Test environment set
(newline)
(display "* Testing custom library *")
(newline)
(display "Testing set-env! Expect 32: ")
(display ((set-env! (lambda () x) '((x . 32)) )))
(newline)
(display "Testing string->datum! Expect (2): ")
(display (cdr (string->datum "(display 2)")))
(newline)
; Test syntax-rules
(header "Testing syntax-rules (move to macro once implemented)")
(define equal? eqv?)
(define construct-pattern-predicate
(lambda (name pat)
(if (if (symbol? pat) #t (number? pat))
`(equal? ,name ',pat)
(if (null? pat)
`(null? ,name)
(if (pair? pat)
`(if (pair? ,name)
(if ,(construct-pattern-predicate `(car ,name) (car pat))
,(construct-pattern-predicate `(cdr ,name) (cdr pat))
#f)
#f)
'fuck )))))
(define syntax-rules-rec
(lambda (macro-name var-name rules)
(if (null? rules)
'doublefuck
(let ((pattern (caar rules))
(result (cadar rules)))
(if (eqv? macro-name (car pattern))
`(if ,(construct-pattern-predicate var-name pattern)
',result
,(syntax-rules-rec macro-name var-name (cdr rules)))
(begin (display "Incorrect usage of syntax-rules-rec: Each rule must have same first symbol.")
(display "\n\tFirst had ")
(display macro-name)
(display "\n\tBut one of them had ")
(display (car pattern))
(newline)))))))
(define-syntax syntax-rules
(lambda (vo)
(let ((literals (cadr vo))
(rules (cddr vo))
(name (car (caaddr vo))))
`(lambda (vo2)
,( syntax-rules-rec name 'vo2 rules))
)))
; Define true
(syntax-rules ()
((name ...) ...))
(define-syntax true
(syntax-rules ()
((true) #t)))
(test "Attempting to define true using syntax rules."
`(
( #t . ,(true))
( #f . ,(not (true)))
))
;
; Below should produce an error:
;(define-syntax bad-rule
;(syntax-rules ()
;((bad-rule-1) #t)
;((bad-rule-2) #f)))
(define-syntax bool
(syntax-rules ()
((bool) #t)
((bool 0) #f)
((bool 1) #t)
))
(test "Attempting to define bool ? using syntax rules."
`(
( #t . ,(bool))
( #f . ,(bool 0))
( #t . ,(bool 1))
))
(define-syntax derp
(syntax-rules ()
((derp) 1)
((derp two) (+ (derp) (derp)))
))
(test "Defining weird macroes using syntax-rules."
`(
( 1 . ,(derp))
( 2 . ,(derp two))
))
;;;;; ;
(exit)
(define-syntax and
(syntax-rules ()
((and) #t)
((and test) test)
((and test1 test2 ...)
(if test1 (and test2 ...) #f))))
(test "Attempting to define and using syntax rules."
`(
(#t . ,(and))
(#f . ,(and #f))
(#t . ,(and #t))
(#f . ,(and #f #f))
(#f . ,(and #t #f))
(#f . ,(and #f #t))
(#t . ,(and #t #t))
(#f . ,(and #t #f #t))
(#f . ,(and #f #f #f))
(#t . ,(and #t #t #t))
(#f . ,(and #f #t #f #f #f #f))
(#t . ,(and #t #t #t #t #t #t))
))
; TODO: Use syntax-rules to implement let and or.
(display "")