aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
diff options
context:
space:
mode:
authorGravatar Peter McGoron 2025-09-01 12:22:58 -0400
committerGravatar Peter McGoron 2025-09-01 12:22:58 -0400
commit11e98ce68d5555ed2e69e4b6baa9d6e5a740464a (patch)
tree6cdf78aa3a0640278317d876c5d7493933890929 /README.md
parentfix missing text (diff)
the rest of r7rs
Diffstat (limited to 'README.md')
-rw-r--r--README.md62
1 files changed, 58 insertions, 4 deletions
diff --git a/README.md b/README.md
index 7a83fda..8ae18a4 100644
--- a/README.md
+++ b/README.md
@@ -9,8 +9,26 @@
HaScheme is a pure, call-by-need dialect of Scheme (R7RS), embedded within
Scheme itself. Procedures in HaScheme can be written in ways that look
-identical to regular Scheme. These procedures return promises which can
-be forced by non-lazy code. Hence lazy and non-lazy code can co-exist.
+identical to regular Scheme. They do not need to be explicitly `delay`ed
+or `delay-force`ed, and they only need to `force` to reduce space usage.
+HaScheme procedures return promises which can be forced by regular
+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
@@ -24,13 +42,31 @@ Why use this?
3. To show those dirty Haskellers that you don't need no stinkin'
static type system.
+## Restrictions and Implementation Notes
+
+1. No `call/cc`. [Explanation](#multiple-values-and-continuations)
+2. No `call-with-values` or multiple-valued returns.
+ [Explanation](#multiple-values-and-continuations)
+3. No exceptions (but `error` exists).
+4. Strings and bytevectors are eager objects. For example, forcing a
+ string will also force any characters and strings used to build
+ the string.
+5. Pairs and vectors are lazy objects. Forcing a pair will not force its
+ components.
+6. No mutation and no I/O (i.e. no ports).
+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.
+8. No quasiquote.
+
## 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:
+in Haskell][HaskellFolds]). Here is an example:
-[1]: https://wiki.haskell.org/Foldr_Foldl_Foldl%27
+[HaskellFolds]: https://wiki.haskell.org/Foldr_Foldl_Foldl%27
(define (list-tail list n)
(if (zero? n)
@@ -115,3 +151,21 @@ takes `n` forms, forces the first `n-1`, and returns the `n`th form.
list
(seq (cdr list)
(list-tail (cdr list) (- n 1)))))
+
+## Multiple Values and Continuations
+
+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
+language can execute any code at basically any time.
+
+A future implementation might be able to use SRFI-226's delimited
+control structures to implement continuations, because they are actual
+functions.
+
+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.