lith/lib.lith

192 lines
4.1 KiB
Plaintext

;;;; lib.lith
;;;; the standard library of lith
(def list (lambda args args))
(macro (func decl body . rest)
(if (eq? (typeof decl) 'pair)
(list 'def (car decl)
(cons 'lambda (cons (cdr decl) (cons body rest))))
(error "func: expected function declaration")))
(func (caar x) (car (car x)))
(func (cadr x) (car (cdr x)))
(func (cdar x) (cdr (car x)))
(func (cddr x) (cdr (cdr x)))
(func (not x) (if x #f #t))
(func (pair? p)
(eq? (typeof p) 'pair))
(func (integer? i)
(eq? (typeof i) 'integer))
(func (number? n)
(eq? (typeof n) 'number))
(func (boolean? n)
(eq? (typeof n) 'boolean))
(func (string? s)
(eq? (typeof s) 'string))
(func (foldl f init lst)
(if (nil? lst)
init
(foldl f (f init (car lst)) (cdr lst))))
(func (map f lst)
(if (nil? lst)
()
(cons (f (car lst)) (map f (cdr lst)))))
(func (foldr f init lst)
(if (nil? lst)
init
(f (car lst) (foldr f init (cdr lst)))))
(func (last lst)
(if (nil? lst)
()
(if (nil? (cdr lst))
(car lst)
(last (cdr lst)))))
(func (reverse lst)
(foldl (lambda (a x) (cons x a)) () lst))
(func (append a b)
(foldr cons b a))
(macro (quasiquote x)
(if (pair? x)
(if (eq? (car x) 'unquote)
(cadr x)
(if (if (pair? (car x)) (eq? (caar x) 'unquote-splicing) #f)
(list 'append
(cadr (car x))
(list 'quasiquote (cdr x)))
(list 'cons
(list 'quasiquote (car x))
(list 'quasiquote (cdr x)))))
(list 'quote x)))
(func (flip f)
(lambda (a b)
(f b a)))
(macro (and . x)
(if (nil? x)
#t
`(if ,(car x) (and . ,(cdr x)) #f)))
(macro (or . x)
(if (nil? x)
#f
`(if ,(car x) #t (or . ,(cdr x)))))
(macro (let env . body)
`((lambda ,(map car env) . ,body) . ,(map cadr env)))
(func (numeric? x)
(or (integer? x) (number? x)))
(func (+ . n)
(foldl :+ 0 n))
(func (* . n)
(foldl :* 1 n))
(func (- . n)
(if (nil? n)
0
(foldl :- (car n) (cdr n))))
(func (/ . n)
(if (nil? n)
1
(foldl :/ (car n) (cdr n))))
(def infinity (:/ 1.0 0.0))
(def -infinity (:/ -1.0 0.0))
(func (:<= a b) (not (:> a b)))
(func (:>= a b) (not (:< a b)))
(func (< a b . c)
(if (nil? c)
(:< a b)
(and (:< a b) (apply < (cons b c)))))
(func (> a b . c)
(if (nil? c)
(:> a b)
(and (:> a b) (apply > (cons b c)))))
(func (= a b . c)
(if (nil? c)
(:== a b)
(and (:== a b) (apply = (cons b c)))))
(func (<= a b . c)
(if (nil? c)
(:<= a b)
(and (:<= a b) (apply <= (cons b c)))))
(func (>= a b . c)
(if (nil? c)
(:>= a b)
(and (:>= a b) (apply >= (cons b c)))))
(func (!= a b)
(not (:== a b)))
(func (mod a b) (:% a b))
(macro (begin a . body)
`((lambda () ,a . ,body)))
(macro (cond . body)
(if (nil? body)
(error "cond: no else clause")
(if (not (pair? (car body)))
(error "cond: expecting a list as clause")
(if (eq? (caar body) 'else)
`(begin . ,(cdar body))
`(if ,(caar body)
(begin . ,(cdar body))
(cond . ,(cdr body)))))))
(func (sign x)
(cond
((not (numeric? x)) (error "sign: input must be numeric"))
((< x 0) -1)
((> x 0) 1)
(else 0)))
(func (filter f lst)
(if (nil? lst)
()
(let ((rest (filter f (cdr lst)))
(cur (car lst)))
(if (f cur)
(cons cur rest)
rest))))
(func (abs x)
(if (< x 0) (- x) x))
(func (divides a b)
(= (mod a b) 0))
(func (1+ x) (+ x 1))
(func (1- x) (- x 1))
(func (range a b)
(if (> a b)
()
(cons a (range (1+ a) b))))
(func (length lst)
(if (nil? lst)
0
(1+ (length (cdr lst)))))
(func (o f g) (lambda (x) (f (g x))))
(func (for-each f lst)
(if (nil? lst)
()
(begin (f (car lst)) (for-each f (cdr lst)))))