blob: dde64f9b1998ddcd75e2ebc2a1867412b885d67b (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
# HaScheme -- Call By Name Scheme
This is a library that exports interfaces similar to the R7RS, except
everything is call-by-need and not call-by-value: there is no need to
explictly use `delay` or `delay-force`. Procedures can be written in
ways that look almost identical to regular Scheme. The procedures
return promises which can be forced by non-lazy code. Hence lazy and
non-lazy code can co-exist.
*Every* procedure in HaScheme is lazy. Values are forced in conditionals,
or explicitly using `!`.
## Fun (or Pain) with Laziness
You need to be careful with lazy functions because they can cause
space leaks. This is a problem in general with lazy languages ([like
in Haskell][1]). Here is an example:
[1]: https://wiki.haskell.org/Foldr_Foldl_Foldl%27
(define (list-tail list n)
(if (zero? n)
list
(list-tail (cdr list) (- n 1))))
Thunks will build up over time in the list, so it must be forced.
(define (list-tail list n)
(if (zero? n)
list
(list-tail (force (cdr list)) (- n 1))))
Note that `n` is never explicitly forced: it is implicitly forced by the
control flow.
The first code block has the attractive property that it operates the
same way on finite lists in both Scheme and HaScheme, while the second
one could differ in exotic cases (like promises that return promises).
Instead of writing `force`, the operator `!` is used:
(define (list-tail list n)
(if (zero? n)
list
(list-tail (! (cdr list)) (- n 1))))
where `(! x)` is defined to just be `x` in Scheme. Now the code block
above operates the same in Scheme and HaScheme.
|