188 lines
5.4 KiB
Racket
188 lines
5.4 KiB
Racket
#lang scribble/doc
|
|
@(require (for-label (except-in lazy delay force)
|
|
(only-in lazy/force ! !! !list !!list)
|
|
scheme/contract
|
|
(only-in scheme/promise promise?)))
|
|
|
|
@(define-syntax-rule (deflazy mod def id)
|
|
(begin
|
|
(def-mz-req mod id mz-id)
|
|
@def[id]{Lazy variant of @|mz-id|.}))
|
|
|
|
@(define-syntax-rule (def-mz-req mod id in-mz-id)
|
|
(begin
|
|
(define-syntax-rule (intro mz-id)
|
|
(begin
|
|
(require (for-label (only-in mod id)))
|
|
(define mz-id (scheme id))))
|
|
(intro in-mz-id)))
|
|
|
|
@(define-syntax-rule (defprocthing* mod id ...)
|
|
(begin
|
|
(deflazy mod defprocthing id)
|
|
...))
|
|
|
|
@(define-syntax-rule (defprocthing id . rest)
|
|
(defthing id procedure? . rest))
|
|
|
|
@(define-syntax-rule (defidform* mod id ...)
|
|
(begin
|
|
(deflazy mod defidform id)
|
|
...))
|
|
|
|
@; ----------------------------------------
|
|
|
|
@(require scribble/manual)
|
|
|
|
@title{@bold{Lazy Racket}}
|
|
|
|
@author["Eli Barzilay"]
|
|
|
|
@defmodulelang[lazy]
|
|
|
|
Lazy Racket is available as both a language level and a module that
|
|
can be used to write lazy code. To write lazy code, simply use
|
|
@schememodname[lazy] as your module's language:
|
|
|
|
@schememod[
|
|
lazy
|
|
... @#,elem{lazy code here}...]
|
|
|
|
Function applications are delayed, and promises are automatically
|
|
forced. The language provides bindings that are equivalent to most of
|
|
the @schememodname[mzscheme] and @schememodname[scheme/list]
|
|
libraries. Primitives are strict in the expected places; struct
|
|
constructors are lazy; @scheme[if], @scheme[and], @scheme[or] @|etc|
|
|
are plain (lazy) functions. Strict functionality is provided as-is:
|
|
@scheme[begin], I/O, mutation, parameterization, etc. To have your
|
|
code make sense, you should chain side effects in @scheme[begin]s,
|
|
which will sequence things properly. (Note: This is similar to
|
|
threading monads through your code---only use @scheme[begin] where
|
|
order matters.)
|
|
|
|
Mixing lazy and strict code is simple: you just write the lazy code in
|
|
the lazy language, and strict code as usual. The lazy language treats
|
|
imported functions (those that were not defined in the lazy language)
|
|
as strict, and on the strict side you only need to force (possibly
|
|
recursively) through promises.
|
|
|
|
A few side-effect bindings are provided as-is. For example,
|
|
@scheme[read] and @scheme[printf] do the obvious thing---but note that
|
|
the language is a call-by-need, and you need to be aware when promises
|
|
are forced. There are also bindings for @scheme[begin] (delays a
|
|
computation that forces all sub-expressions), @scheme[when],
|
|
@scheme[unless], etc. There are, however, less reliable and might
|
|
change (or be dropped) in the future.
|
|
|
|
There are a few additional bindings, the important ones are special
|
|
forms that force strict behaviour---there are several of these that
|
|
are useful in forcing different parts of a value in different ways, as
|
|
described in @secref["forcing"].
|
|
|
|
@; ----------------------------------------
|
|
|
|
@section{Lazy Forms and Functions}
|
|
|
|
@defidform*[mzscheme
|
|
lambda
|
|
define
|
|
]
|
|
|
|
@defidform*[scheme
|
|
let
|
|
let*
|
|
letrec
|
|
parameterize
|
|
define-values
|
|
let-values
|
|
let*-values
|
|
letrec-values
|
|
if
|
|
set!
|
|
begin begin0 when unless
|
|
cond case
|
|
]
|
|
|
|
@defprocthing*[scheme
|
|
values make-struct-type
|
|
cons list list* vector box
|
|
and or
|
|
set-mcar! set-mcdr! vector-set! set-box!
|
|
error printf fprintf display write print
|
|
eq? eqv? equal?
|
|
list? length list-ref list-tail append map for-each andmap ormap
|
|
member memq memv assoc assq assv reverse
|
|
caar cadr cdar cddr caaar caadr cadar caddr cdaar cdadr cddar cdddr caaaar
|
|
caaadr caadar caaddr cadaar cadadr caddar cadddr cdaaar cdaadr cdadar cdaddr
|
|
cddaar cddadr cdddar cddddr
|
|
first second third fourth fifth sixth seventh eighth rest cons? empty empty?
|
|
foldl foldr last-pair remove remq remv remove* remq* remv* memf assf filter
|
|
sort
|
|
true false boolean=? symbol=? compose build-list
|
|
take
|
|
]
|
|
|
|
@defprocthing[identity]{Lazy identity function.}
|
|
|
|
@defprocthing[cycle]{Creates a lazy infinite list given a list of
|
|
elements to repeat in order.}
|
|
|
|
@; ----------------------------------------
|
|
|
|
@section[#:tag "forcing"]{Forcing Values}
|
|
|
|
@defmodule[lazy/force]
|
|
|
|
The bindings of @schememodname[lazy/force] are re-provided by
|
|
@schememodname[lazy].
|
|
|
|
@defproc[(! [expr any/c]) any/c]{
|
|
|
|
Evaluates @scheme[expr] strictly. The result is always forced, over
|
|
and over until it gets a non-promise value.}
|
|
|
|
|
|
@defproc[(!![expr any/c]) any/c]{
|
|
|
|
Similar to @scheme[!], but recursively forces a structure (e.g:
|
|
lists).}
|
|
|
|
|
|
@defproc[(!list [expr (or/c promise? list?)]) list?]{
|
|
|
|
Forces the @scheme[expr] which is expected to be a list, and forces
|
|
the @scheme[cdr]s recursively to expose a proper list structure.}
|
|
|
|
|
|
@defproc[(!!list [expr (or/c promise? list?)]) list?]{
|
|
|
|
Similar to @scheme[!list] but also forces (using @scheme[!]) the
|
|
elements of the list.}
|
|
|
|
|
|
@;{ This moved into lazy.ss, and all the other forces will move there too.
|
|
|
|
@subsection{Multiple values}
|
|
|
|
To avoid dealing with multiple values, they are treated as a single
|
|
tuple in the lazy language. This is implemented as a
|
|
@scheme[multiple-values] struct, with a @scheme[values] slot.
|
|
|
|
@defproc[(split-values [x multiple-values?]) any]{
|
|
|
|
Used to split such a tuple to actual multiple values. (This may change
|
|
in the future.)}
|
|
|
|
|
|
@defproc[(!values [expr (or/c promise? multiple-values?)]) any]{
|
|
|
|
Forces @scheme[expr] and uses @scheme[split-values] on the result.}
|
|
|
|
|
|
@defproc[(!!values [expr (or/c promise? multiple-values?)]) any]{
|
|
|
|
Similar to @scheme[!values], but forces each of the values
|
|
recursively.}
|
|
|
|
;}
|