aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
diff options
context:
space:
mode:
authorGravatar Peter McGoron 2026-03-08 09:08:14 -0400
committerGravatar Peter McGoron 2026-03-08 09:08:14 -0400
commit11ba05b6ac0c7365ac000a23a8024c316c4983d8 (patch)
tree584a51c708e616cb76ad354909b37f02137322f6 /README.md
parent0.2.0 (diff)
first attempt at moving over to SRFI-259
Diffstat (limited to 'README.md')
-rw-r--r--README.md100
1 files changed, 74 insertions, 26 deletions
diff --git a/README.md b/README.md
index 3ab935b..4afab6d 100644
--- a/README.md
+++ b/README.md
@@ -7,12 +7,11 @@
>
> -- Revisedⁿ Reports on the Algorithmic Language Scheme (n ≥ 3, 1986–)
-HaScheme is a library that implements a subset of the R7RS's libraries
-in a lazy way, using `force` and `delay-force`. When HaScheme is used
-by itself, it is a lazy functional programming language with the same
-syntax as Scheme, embedded within Scheme.
+HaScheme is a library that implements a subset of the R⁷RS in a lazy
+way. When HaScheme is used by itself, it is a lazy functional programming
+language with the same syntax as Scheme, embedded within Scheme.
-For instance, the following `map` implementation is both valid HaScheme
+For example, the following `map` implementation is both valid HaScheme
(importing `(hascheme base)`) and Scheme (importing `(scheme base)`):
(define (map f list)
@@ -33,25 +32,13 @@ code. HaScheme's datatypes are the same as regular Schemes. Hence lazy
and non-lazy code can co-exist. It is easy to wrap eager Scheme procedures
to be usable in HaScheme.
-HaScheme should run in any R7RS-compatible system that distinguishes
-promises from all other types, and that allows forcing non-promises.
-There is no need to support implicit forcing.
-
-HaScheme uses `delay-force`, which is not available in R6RS. HaScheme
-could be implemented on top of [SRFI-45][SRFI-45] if the representation
-of promises was changed to a `define-record-type` datatype instead of
-cons cells.
-
-See also [Lazy Racket][LazyRacket].
-
-[LazyRacket]: https://docs.racket-lang.org/lazy/index.html
-[SRFI-45]: https://srfi.schemers.org/srfi-45
-
*Every* procedure in HaScheme is lazy. Values are forced in conditionals,
or explicitly using `seq`. This allows for the call-by-value semantics
of Scheme to be turned into call-by-need semantics without any syntactic
cruft.
+HaScheme should run in any implemention of the R⁷RS.
+
Why use this?
1. To have fun playing around with functional infinite data structures.
@@ -59,6 +46,12 @@ Why use this?
3. To show those dirty Haskellers that you don't need no stinkin'
static type system.
+See also [Lazy Racket][LazyRacket].
+
+[LazyRacket]: https://docs.racket-lang.org/lazy/index.html
+
+HaScheme is licensed under the 0BSD license.
+
## Restrictions and Implementation Notes
1. No `call/cc`. [Explanation](#multiple-values-and-continuations)
@@ -74,7 +67,7 @@ Why use this?
7. Parameters are not supported because forcing a promise uses the
parameters of the dynamic extent of the force, and not the dynamic
extent of the delay. This makes them useless in this context.
- This would be fixed by SRFI-226.
+ This would be fixed by SRFI 226.
8. No quasiquote.
## Fun (or Pain) with Laziness
@@ -174,7 +167,7 @@ takes `n` forms, forces the first `n-1`, and returns the `n`th form.
HaScheme doesn't have `call/cc`. `call/cc` is not a function because it
does not return, so that's strike one for inclusion in a pure language.
Reified continuations make sense in a call-by-value language, because
-there is a definite evaluation order (outermost first), but a lazy
+there is a definite evaluation order (innermost first), but a lazy
language can execute any code at basically any time.
A future implementation might be able to use SRFI-226's delimited
@@ -185,10 +178,65 @@ Multiple values are specified as returning values to their continuation.
Since HaScheme does not (conceptually) have continuations, multiple
values have to be interpreted differently. But a bigger issue occurs
because a promise is a single value. It cannot be decomposed into more
-values without forcing the promise.
+values without forcing the promise. Multiple value returns are simulated
+using lists, although vectors could also work.
+
+## Why `delay` and `delay-force` Are Not Enough
+
+Scheme for a long time had `delay` and `force` that were never implemented
+very well. It was only in the R⁷RS that they were implemented in a
+safe-for-space way. However, the usual transformation does not handle
+higher-order procedures correctly.
-## License
+For example, consider the transformation advocated in [SRFI 45][SRFI-45].
+The `map` function, defined as
-0BSD for everything except for `(hascheme implemetation-support)`, which
-implements a modified version of the SRFI-45 sample implementation for
-systems that do not implement the requirements for promises here.
+ (define (map f lst)
+ (if (null? lst)
+ '()
+ (cons (f (car lst)) (map f (cdr lst)))))
+
+becomes
+
+ (define (map f lst)
+ (delay-force
+ (if (null? (force lst))
+ (delay '())
+ (delay (cons (f (car (force lst)))
+ (map f (cdr (force lst))))))))
+
+So far, so good. But let us define
+
+ (define (add-n n)
+ (lambda (x)
+ (+ x n)))
+
+which then becomes
+
+ (define (add-n n)
+ (delay-force
+ (lambda (x)
+ (delay-force (+ (force x) (force n))))))
+
+If we evaluated, in normal Scheme,
+
+ (map (add-n 5) '(1 2 3 4))
+
+we would get `(6 7 8 9)` back. But if we evaluated this in our lazy
+language, we would get an error because we tried to apply arguments to
+a non-procedure.
+
+We could get around this by annotating each higher-order procedure with
+`force`. But this violates one of the principles of HaScheme, which is that
+the code should look natural.
+
+Instead, this library uses [SRFI 259][SRFI-259] tagged procedures to wrap
+promises. This allows for arbitrary higher-order procedures expressed
+in a natural way.
+
+Each `lambda` creates a procedure object that can be called with an
+arbitrary number of arguments to create another procedure. Procedure
+argument length is only checked when the procedure is forced.
+
+[SRFI-45]: https://srfi.schemers.org/srfi-45
+[SRFI-259]: https://srfi.schemers.org/srfi-259