(fold + 0 '(1 2 3 4)) |
(define (fold proc acc list)
(if (null? list)
acc
(fold proc (proc (car list) acc) (cdr list))))
|
(define (1+ x) (+ x 1)) (unfold 0 (lambda (x) (>= x 10)) 1+) |
(define (unfold init end? next)
(let loop ((value init) (list '()))
(if (end? value)
(reverse list)
(loop (next value) (cons value list)))))
|
for (int i = 0; i < my_size; i++)
do_something( my_array[i] );
|
struct point3d_t
{
int x;
int y;
int z;
};
|
(define (make-point3d x y z) (list x y z)) (define (point3d-x point) (car point)) (define (point3d-y point) (cadr point)) (define (point3d-z point) (caddr point)) (define-macro (with-point3d point . body) `(apply (lambda (x y z) ,@body) ,point)) |
Хозяйке на заметкуЕсли ваш интерпретатор схемы не поддерживает макросы в стиле Common Lisp (define-macro), можно воспользоваться стандартным схемовским define-syntax, поменяв синтаксис макроса |
(define (make-point3d x y z)
(list->vector (list x y z)))
(define (point3d-x point) (vector-ref point 0))
(define (point3d-y point) (vector-ref point 1))
(define (point3d-z point) (vector-ref point 2))
(define-macro (with-point3d point . body)
`(let ((x (point3d-x ,point))
(y (point3d-y ,point))
(z (point3d-z ,point)))
,@body))
|
(define (make-point3d . args) (apply list->vector args)) |
(define (make-adder a) (lambda (x) (+ x a))) (define add-7 (make-adder 7)) (define add-8 (make-adder 8)) (add-7 4) (add-8 4) |
(define (make-point3d x y z) (lambda () ???) |
(define (make-point3d x y z) (lambda (code) (code x y z))) (define (point3d-x point) (point (lambda (x y z) x))) (define (point3d-y point) (point (lambda (x y z) y))) (define (point3d-z point) (point (lambda (x y z) z))) (define-macro (with-point3d point . body) `(,point (lambda (x y z) ,@body))) |
(define (s+ . symbols)
(string->symbol (apply string-append
(map symbol->string symbols))))
(define-macro (define-type name . fields)
`(begin
(define (,(s+ 'make- name) ,@fields)
(lambda (code) (code ,@fields)))
,@(map (lambda (f)
`(define (,(s+ name '- f) type)
(type (lambda (,@fields) ,f)))) fields)
,(apply define-with-macro name fields)))
(define (define-with-macro name . fields)
`(define-macro (,(s+ 'with- name) type . body)
(list type (append (list 'lambda '(,@fields)) body))))
|
Хозяйке на заметкуВ вышеприведенном коде имеет смысл обратить внимание на участок с with-: мы имеем макрос, который генерирует другой макрос, который генерирует код :) При желании, подобным образом можно добавить дополнительные инструменты, вроде with-modify-. |
(define-type point3d x y z) |
(define-type avl-tree root less? equ?) |
(define (make-empty-avl-tree less? equ?) (make-avl-tree #f less? equ?)) |
(define-type avl-node key value l-child r-child l-depth r-depth) |
(define (avl-tree-insert tree key value)
(with-avl-tree tree
(make-avl-tree
(avl-tree-insert-node root key value less?)
less?
equ?)))
|
(define (avl-tree-insert-node node ckey cvalue less?)
(if (not node)
(make-avl-node ckey cvalue #f #f 0 0)
(let ((args (list node ckey cvalue less?)))
(with-avl-node node
(if (less? ckey key)
(apply avl-subtree-insert-node
make-left l-child l-depth args)
(apply avl-subtree-insert-node
make-right r-child r-depth args))))))
(define (avl-subtree-insert-node make-proc child depth node . args)
(let ((new-child (apply avl-tree-insert-node child args)))
(with-avl-node new-child
(make-proc node new-child (calc-depth new-child)))))
|
(define (make-left node child depth)
(with-avl-node node
(make-avl-node key value child r-child depth r-depth)))
(define (make-right node child depth)
(with-avl-node node
(make-avl-node key value l-child child l-depth depth)))
|
(define (calc-depth node) (with-avl-node node (1+ (max l-depth r-depth)))) |
![]() Рис. 1: добавление элемента |
Хозяйке на заметкуЕсли быть точным, то высота AVL-дерева ограничена сверху значением 1.44 * log2N. |
![]() Рис. 2: правая ротация |
--- 1,11 ----
(define (avl-tree-insert-node node ckey cvalue less?)
(if (not node)
(make-avl-node ckey cvalue #f #f 0 0)
+ (avl-tree-check-rotate
(let ((args (list node ckey cvalue less?)))
(with-avl-node node
(if (less? ckey key)
(apply avl-subtree-insert-node
make-left l-child l-depth args)
(apply avl-subtree-insert-node
! make-right r-child r-depth args)))))))
|
(define (avl-tree-check-rotate node)
(with-avl-node node
(cond ((and (> l-depth r-depth)
(> (- l-depth r-depth) 1))
(apply avl-tree-rotate node rotate-right-set))
((and (> r-depth l-depth)
(> (- r-depth l-depth) 1))
(apply avl-tree-rotate node rotate-left-set))
(else node))))
(define rotate-right-set (list make-right
avl-node-l-child
make-left
avl-node-r-child
avl-node-r-depth))
(define rotate-left-set (list make-left
avl-node-r-child
make-right
avl-node-l-child
avl-node-l-depth))
(define (avl-tree-rotate node make-a get-child-a make-b get-child-b get-depth-b)
(let* ((child-a (get-child-a node))
(child-b (get-child-b child-a))
(depth-b (get-depth-b child-a)))
(let ((new-node (make-b node child-b depth-b)))
(make-a child-a new-node (calc-depth new-node)))))
|
(define (fill list)
(fold (lambda (k t) (avl-tree-insert t k #t))
(make-empty-avl-tree < =)
list))
|
(calc-depth (avl-tree-root (fill (unfold 0 (lambda (x) (>= x 1e6)) 1+)))) |
(define (avl-tree-lookup tree ckey)
(with-avl-tree tree
(let lookup ((node root))
(if (not node)
#f
(with-avl-node node
(cond ((equ? ckey key) value)
((less? ckey key) (lookup l-child))
(else (lookup r-child))))))))
|
Хозяйке на заметкуСтрого говоря, если вдаваться немного в подробности, в функциональном программировании есть интересный трюк, благодаря которому такой процесс протаскивания контенста можно автоматизировать и скрыть с глаз вообще, называется: "Монада". Но про монады я, пожалуй, расскажу в другой статье, а пока мы реализуем обход дерева в рамках fold. |
(define (avl-tree-fold tree proc acc)
(with-avl-tree tree
(let traverse ((node root) (c-acc acc))
(if (not node)
c-acc
(with-avl-node node
(let* ((l-val (traverse l-child c-acc))
(c-val (proc key value l-val))
(r-val (traverse r-child c-val)))
r-val))))))
|
(define (avl-tree-max-value tree) (avl-tree-fold tree (lambda (k v a) (max v a)) 0)) |
(define (avl-tree-double-copy tree)
(avl-tree-fold tree
(lambda (k v t) (avl-tree-insert t (* k 2) v))
(make-empty-avl-tree (avl-tree-less? tree)
(avl-tree-equ? tree))))
|
(define (avl-tree-insert tree key value)
(avl-tree-replace tree key (lambda (x) value)))
(define (avl-tree-replace tree key value-proc)
(with-avl-tree tree
(make-avl-tree
(avl-tree-insert-node root key value-proc less? equ?)
less?
equ?)))
|
--- 1,22 ----
! (define (avl-tree-insert-node node ckey value-proc less? equ?)
(if (not node)
! (make-avl-node ckey (value-proc #f) #f #f 0 0)
(avl-tree-check-rotate
! (let ((args (list node ckey value-proc less? equ?)))
(with-avl-node node
! (cond ((equ? ckey key)
! (make-avl-node key (value-proc value) l-child r-child l-depth r-depth))
! ((less? ckey key)
(apply avl-subtree-insert-node
make-left l-child l-depth args))
! (else
(apply avl-subtree-insert-node
make-right r-child r-depth args))))))))
|
(define-type queue left-list right-list length) (define (make-empty-queue) (make-queue '() '() 0)) |
(define (queue-empty? queue) (zero? (queue-length queue))) |
(define (queue-insert queue element)
(with-queue queue
(make-queue left-list
(cons element right-list)
(1+ length))))
|
(define-type remove-result
value
queue)
(define (queue-remove queue)
(with-queue queue
(cond ((zero? length) (make-remove-result #f queue))
((null? left-list)
(queue-remove (make-queue (reverse right-list)
'()
length)))
(else (make-remove-result (car left-list)
(make-queue (cdr left-list)
right-list
(1- length)))))))
|
(define (list->queue list)
(fold (lambda (e q) (queue-insert q e))
(make-empty-queue)
list))
(define (queue->list queue)
(let traverse ((queue queue) (list '()))
(if (queue-empty? queue)
(reverse list)
(with-remove-result (queue-remove queue)
(traverse queue (cons value list))))))
|
(define (queue-filter queue check?)
(let traverse ((queue queue) (result-queue (make-empty-queue)))
(if (queue-empty? queue)
result-queue
(with-remove-result (queue-remove queue)
(traverse queue
(if (check? value)
(queue-insert result-queue value)
result-queue))))))
|
(define-type hash-vector
vector
hash-proc
equ?)
(define (avl-tree->hash-vector tree table-size hash-proc)
(let ((vector (make-vector table-size '()))
(hash-proc (lambda (x) (modulo (hash-proc x) table-size))))
(avl-tree-fold tree
(lambda (k v a)
(let* ((index (hash-proc k))
(cell (cons k v))
(list (vector-ref vector index)))
(vector-set! vector index (cons cell list))))
(void))
(make-hash-vector vector hash-proc (avl-tree-equ? tree))))
|
(define (assoc-ex key list =)
(cond ((null? list) #f)
((= key (caar list)) (car list))
(else (assoc-ex key (cdr list) =))))
(define (hash-vector-lookup hash-vector key)
(with-hash-vector hash-vector
(let* ((index (hash-proc key))
(list (vector-ref vector index))
(value (assoc-ex key list equ?)))
(if value (cdr value) #f))))
|
(define-type hash-tree
tree
size
table-size
hash-proc
equ?
load-factor)
(define (make-empty-hash-tree table-size hash-proc equ? load-factor)
(make-hash-tree (let loop ((index 0)
(tree (make-empty-avl-tree < =)))
(if (>= index table-size)
tree
(loop (1+ index)
(avl-tree-insert tree index '()))))
0
table-size
hash-proc
equ?
load-factor))
(define (hash-tree-resize htree new-size)
(with-hash-tree htree
(avl-tree-fold (hash-tree-tree htree)
(lambda (index list tree)
(fold (lambda (v t)
(hash-tree-insert t (car v) (cdr v)))
tree
list))
(make-empty-hash-tree new-size
hash-proc
equ?
load-factor))))
(define (hash-tree-insert htree key value)
(with-hash-tree htree
(if (>= (/ size table-size) load-factor)
(let ((new-tree (hash-tree-resize htree
(* table-size 2))))
(hash-tree-insert new-tree key value))
(make-hash-tree
(let ((index (modulo (hash-proc key) table-size)))
(avl-tree-replace tree
index
(lambda (list)
(cons (cons key value) list))))
(1+ size) table-size hash-proc equ? load-factor))))
(define (hash-tree-lookup htree key)
(with-hash-tree htree
(let* ((index (modulo (hash-proc key) table-size))
(list (avl-tree-lookup tree index))
(value (assoc-ex key list equ?)))
(if value (cdr value) #f))))
|