doc: Fix typos.
[jackhill/guix/guix.git] / guix / combinators.scm
CommitLineData
958dd3ce
LC
1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2012, 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
3;;; Copyright © 2014 Eric Bavier <bavier@member.fsf.org>
4;;;
5;;; This file is part of GNU Guix.
6;;;
7;;; GNU Guix is free software; you can redistribute it and/or modify it
8;;; under the terms of the GNU General Public License as published by
9;;; the Free Software Foundation; either version 3 of the License, or (at
10;;; your option) any later version.
11;;;
12;;; GNU Guix is distributed in the hope that it will be useful, but
13;;; WITHOUT ANY WARRANTY; without even the implied warranty of
14;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;;; GNU General Public License for more details.
16;;;
17;;; You should have received a copy of the GNU General Public License
18;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
19
20(define-module (guix combinators)
21 #:use-module (ice-9 match)
22 #:use-module (ice-9 vlist)
23 #:export (memoize
24 fold2
25 fold-tree
26 fold-tree-leaves
27 compile-time-value))
28
29;;; Commentary:
30;;;
31;;; This module provides useful combinators that complement SRFI-1 and
32;;; friends.
33;;;
34;;; Code:
35
36(define (memoize proc)
37 "Return a memoizing version of PROC."
38 (let ((cache (make-hash-table)))
39 (lambda args
40 (let ((results (hash-ref cache args)))
41 (if results
42 (apply values results)
43 (let ((results (call-with-values (lambda ()
44 (apply proc args))
45 list)))
46 (hash-set! cache args results)
47 (apply values results)))))))
48
49(define fold2
50 (case-lambda
51 ((proc seed1 seed2 lst)
52 "Like `fold', but with a single list and two seeds."
53 (let loop ((result1 seed1)
54 (result2 seed2)
55 (lst lst))
56 (if (null? lst)
57 (values result1 result2)
58 (call-with-values
59 (lambda () (proc (car lst) result1 result2))
60 (lambda (result1 result2)
61 (loop result1 result2 (cdr lst)))))))
62 ((proc seed1 seed2 lst1 lst2)
63 "Like `fold', but with a two lists and two seeds."
64 (let loop ((result1 seed1)
65 (result2 seed2)
66 (lst1 lst1)
67 (lst2 lst2))
68 (if (or (null? lst1) (null? lst2))
69 (values result1 result2)
70 (call-with-values
71 (lambda () (proc (car lst1) (car lst2) result1 result2))
72 (lambda (result1 result2)
73 (fold2 proc result1 result2 (cdr lst1) (cdr lst2)))))))))
74
75(define (fold-tree proc init children roots)
76 "Call (PROC NODE RESULT) for each node in the tree that is reachable from
77ROOTS, using INIT as the initial value of RESULT. The order in which nodes
78are traversed is not specified, however, each node is visited only once, based
79on an eq? check. Children of a node to be visited are generated by
80calling (CHILDREN NODE), the result of which should be a list of nodes that
81are connected to NODE in the tree, or '() or #f if NODE is a leaf node."
82 (let loop ((result init)
83 (seen vlist-null)
84 (lst roots))
85 (match lst
86 (() result)
87 ((head . tail)
88 (if (not (vhash-assq head seen))
89 (loop (proc head result)
90 (vhash-consq head #t seen)
91 (match (children head)
92 ((or () #f) tail)
93 (children (append tail children))))
94 (loop result seen tail))))))
95
96(define (fold-tree-leaves proc init children roots)
97 "Like fold-tree, but call (PROC NODE RESULT) only for leaf nodes."
98 (fold-tree
99 (lambda (node result)
100 (match (children node)
101 ((or () #f) (proc node result))
102 (else result)))
103 init children roots))
104
105(define-syntax compile-time-value ;not quite at home
106 (syntax-rules ()
107 "Evaluate the given expression at compile time. The expression must
108evaluate to a simple datum."
109 ((_ exp)
110 (let-syntax ((v (lambda (s)
111 (let ((val exp))
112 (syntax-case s ()
113 (_ #`'#,(datum->syntax s val)))))))
114 v))))
115
116;;; combinators.scm ends here