2008-07-07 19:07:48 +04:00
|
|
|
;;
|
|
|
|
;; common functions for capone
|
|
|
|
;;
|
|
|
|
|
|
|
|
(define first car)
|
|
|
|
(define rest cdr)
|
|
|
|
|
2008-10-30 18:24:19 +03:00
|
|
|
;; inc/dec family
|
2008-07-14 17:58:42 +04:00
|
|
|
(define (inc n)
|
|
|
|
(+ 1 n))
|
|
|
|
|
|
|
|
(define (dec n)
|
|
|
|
(- n 1))
|
|
|
|
|
|
|
|
(define-macro (inc! n)
|
|
|
|
`(set! ,n (+ 1 ,n)))
|
|
|
|
|
|
|
|
(define-macro (dec! n)
|
|
|
|
`(set! ,n (- ,n 1)))
|
|
|
|
|
2008-11-03 16:02:38 +03:00
|
|
|
(define-macro (if-not . body)
|
|
|
|
`(if (not ,(car body))
|
|
|
|
,@(cdr body)))
|
|
|
|
|
2008-07-07 19:07:48 +04:00
|
|
|
;;
|
|
|
|
;; Allow defining functions like:
|
|
|
|
;; (def name (param1 param2)
|
|
|
|
;; ...
|
|
|
|
;; )
|
|
|
|
(define-macro (def name . rest)
|
|
|
|
;; name - function name
|
|
|
|
;; (car rest) - function params
|
|
|
|
;; (cdr rest)- function body
|
|
|
|
`(define ,(cons name (car rest))
|
|
|
|
,@(cdr rest)))
|
|
|
|
|
|
|
|
;;
|
|
|
|
;; Flexible printing e.g.:
|
|
|
|
;; (define num 3)
|
|
|
|
;; (print "This number is: " num "\n")
|
|
|
|
;;
|
|
|
|
(define (print arg . rest)
|
|
|
|
(display arg)
|
|
|
|
(let loop ((rest rest))
|
|
|
|
(if (not (null? rest))
|
|
|
|
(begin
|
|
|
|
(display (car rest))
|
|
|
|
(loop (cdr rest))))))
|
|
|
|
|
|
|
|
;;
|
|
|
|
;; (print) with newline
|
|
|
|
;;
|
|
|
|
(define-macro (println . body)
|
|
|
|
`(print ,@body "\n"))
|
|
|
|
|
|
|
|
;;
|
|
|
|
;; while loop macro; used like:
|
|
|
|
;; (while (> a 2)
|
|
|
|
;; ...
|
|
|
|
;; )
|
|
|
|
;;
|
|
|
|
(define-macro (while . body)
|
|
|
|
`(let loop ()
|
|
|
|
;; fetch condition
|
|
|
|
(if ,(car body)
|
|
|
|
(begin
|
|
|
|
;; evaluate body
|
|
|
|
,@(cdr body)
|
|
|
|
(loop)))))
|
|
|
|
|
|
|
|
;;
|
|
|
|
;; A python-like 'for' loop, works only on lists, like:
|
|
|
|
;; (for i in '(1 2 3 4 5)
|
|
|
|
;; (print "Number is " i "\n")
|
|
|
|
;; )
|
|
|
|
(define-macro (for . expr)
|
|
|
|
;; (car expr) is 'i'
|
|
|
|
;; (caddr expr) is list
|
|
|
|
;; (cdddr expr) is body
|
|
|
|
(let* (( lst (gensym) ))
|
|
|
|
`(let (( ,lst ,(caddr expr) ))
|
|
|
|
(cond
|
|
|
|
((list? ,lst)
|
|
|
|
(map (lambda (,(car expr))
|
|
|
|
,@(cdddr expr))
|
|
|
|
,lst))
|
|
|
|
(else
|
|
|
|
(throw "Unsupported type in 'for' loop"))))))
|
|
|
|
|
2008-11-04 13:32:58 +03:00
|
|
|
;;
|
|
|
|
;; Split a list to a list of pairs so we can easily
|
|
|
|
;; embed it in 'let' expression via 'slet' macro
|
|
|
|
;; e.g. (1 2 3 4) => ((1 2) (3 4))
|
|
|
|
;;
|
|
|
|
(define (explode-list lst)
|
|
|
|
(let loop ((lst lst)
|
|
|
|
(n '()))
|
|
|
|
(if (null? lst)
|
|
|
|
(reverse n)
|
|
|
|
(begin
|
|
|
|
;; huh...
|
|
|
|
(set! n (cons (list (car lst) (cadr lst)) n))
|
|
|
|
(loop (cddr lst) n)
|
|
|
|
))))
|
|
|
|
|
|
|
|
;;
|
|
|
|
;; slet or 'simplified let' is a 'let' with little less bracess
|
|
|
|
;; e.g. (let (a 1 b 2) body)
|
|
|
|
;;
|
|
|
|
(define-macro (slet . body)
|
|
|
|
`(let ,@(list (explode-list (car body)))
|
|
|
|
,@(cdr body)
|
|
|
|
))
|
|
|
|
|
|
|
|
(define-macro (slet* . body)
|
|
|
|
`(let* ,@(list (explode-list (car body)))
|
|
|
|
,@(cdr body)
|
|
|
|
))
|
|
|
|
|
2008-07-07 19:07:48 +04:00
|
|
|
;;
|
2008-07-18 16:34:35 +04:00
|
|
|
;; range function; returns a list of numbers in form [start end)
|
2008-07-07 19:07:48 +04:00
|
|
|
;;
|
2008-07-18 16:34:35 +04:00
|
|
|
;; Althought we could wrote this function cleanly without decrementors
|
|
|
|
;; using recursion call after 'cons', we would loose tail call optimization
|
|
|
|
;; yielding much slower function.
|
|
|
|
;;
|
|
|
|
(define (range start end)
|
|
|
|
(let loop ((s (- start 1))
|
|
|
|
(e (- end 1))
|
2008-07-07 19:07:48 +04:00
|
|
|
(lst '()))
|
2008-07-18 16:34:35 +04:00
|
|
|
(if (>= s e)
|
2008-07-07 19:07:48 +04:00
|
|
|
lst
|
2008-07-18 16:34:35 +04:00
|
|
|
(loop s (- e 1) (cons e lst)))))
|
|
|
|
|
|
|
|
;;
|
|
|
|
;; iota function; returns a list of numbers
|
|
|
|
;;
|
|
|
|
(define (iota n)
|
|
|
|
(range 0 n))
|
2008-07-14 14:42:25 +04:00
|
|
|
|
2008-10-30 18:24:19 +03:00
|
|
|
;;
|
|
|
|
;; Inplace vector shuffle via Fisher-Yates algorithm
|
|
|
|
;;
|
|
|
|
(define (shuffle-vector! v)
|
|
|
|
(let ((i (vector-length v))
|
|
|
|
(k 0)
|
|
|
|
(tmp 0))
|
|
|
|
(while (> i 1)
|
|
|
|
(set! k (modulo (random-next) i))
|
|
|
|
(dec! i)
|
|
|
|
(set! tmp (vector-ref v i))
|
|
|
|
(vector-set! v i (vector-ref v k))
|
|
|
|
(vector-set! v k tmp)
|
|
|
|
)))
|
|
|
|
|
2008-07-14 14:42:25 +04:00
|
|
|
;;
|
|
|
|
;; function for easier timing
|
|
|
|
;;
|
|
|
|
(define (timeit proc)
|
|
|
|
(let ((v1 0)
|
|
|
|
(v2 0))
|
|
|
|
|
|
|
|
(set! v1 (clock))
|
|
|
|
(proc)
|
|
|
|
(set! v2 (clock))
|
|
|
|
;; 1000000 is value of CLOCKS_PER_SEC
|
|
|
|
(/ (- v2 v1) 1000000)))
|
2008-07-15 20:00:41 +04:00
|
|
|
|
|
|
|
(define *timeit-start-value* 0)
|
|
|
|
(define *timeit-end-value* 0)
|
|
|
|
|
|
|
|
(define (timeit-start)
|
|
|
|
(set! *timeit-start-value* (clock)))
|
|
|
|
|
|
|
|
(define (timeit-end)
|
|
|
|
(set! *timeit-end-value* (clock)))
|
|
|
|
|
|
|
|
(define (timeit-result)
|
|
|
|
(/ (- *timeit-end-value* *timeit-start-value*) 1000000))
|