source: project/wiki/eggref/5/messages @ 37348

Last change on this file since 37348 was 37348, checked in by juergen, 3 years ago

messages docu updated

File size: 11.0 KB
Line 
1[[tags: egg]]
2
3== messages
4
5[[toc:]]
6
7=== Description
8
9An implementation of algebraic, abstract and object types. Algebraic
10types are discriminated variant records, as advocated in the classic
11"Essentials of Programming Languages" by Friedman, Wand and Haynes and
12named datatype there.  They were ported to Chicken by Felix Winkelmann.
13Here, they are implemented via messages, i.e functional vectors tagged
14with a type- and a variant-key, and accessed via case-variant, a small
15wrapper around bind-case from the bindings module.
16
17Note that the arguments of variant constructors can accept zero or
18multiple predicates.
19
20Abstract types are based on algebraic types, but hide the variant
21constructors and export constructor and accessor procedures instead.
22
23Object types export message handlers as well as the messages understood
24by that handler, the latter being created by constructors of algebraic
25types. The message handlers are procedures closed over some state, so
26they can be identified with the objects itself.
27
28All three types implement some sort of inheritance via delegation. To
29avoid different names for different levels of inheritance, the
30constructors and the exported routines of abstract types are curried
31and tagged with keywords. For example, if Foo is a type and #:bar is the
32tag of some variant, the actual constructor is (Foo #:bar). This has the
33drawback to be heavy on the fingers but the advantage, that different
34types may have the same symbol discriminator.
35 
36This documentation uses special ellipses meaning
37* two dots: zero or one
38* three dots: zero or many
39* four dots: one or many
40occurences of the item to its left.
41
42=== functional vectors
43
44==== functional-vectors
45<procedure> (functional-vectors sym ..)</procedure>
46documentation procedure
47
48==== fvector
49<procedure (fvector . args)</procedure>
50type constructor
51
52==== fvector?
53<procedure> (fvector? xpr)</procedure>
54type predicate
55
56==== fvector-ref
57<procedure (fvector-ref fv k)</procedure>
58accessor
59
60==== fvector-tail
61<procedure> (fvector-tail fv k)</procedure>
62accessor
63
64==== fvector-data
65<procedure> (fvector-data fv)</procedure>
66transforms a (possibly nested) fvector
67into a (possibly nested) list
68
69=== messages
70
71==== messages
72
73<procedure>(messages sym ..)</procedure>
74
75documenatation procedure.
76shows the list of available exported symbols of the module when called
77without argument or the signature of that very argument.
78
79==== make-message
80
81<procedure>(make-message type-key key . args)</procedure>
82
83type constructor
84
85==== message?
86
87<procedure>(message? xpr)</procedure>
88
89type predicate
90
91==== message-of?
92
93<procedure>(message-of? type-key)</procedure>
94
95returns a predicate which checks, if its only argument
96is a message of the given type-key
97
98==== message-key
99
100<procedure> (message-key msg)</procedure>
101
102returns the key of a message
103
104==== message-type
105
106<procedure>(message-type msg)</procedure>
107
108returns the type-key of a message
109
110==== message-data
111
112<procedure>(message-data msg)</procedure>
113
114returns the data vector of the message.
115
116==== case-variant
117
118<macro>(case-variant type obj variant ....)</macro>
119
120where each variant is either of the form
121
122* (variant-key (arg ...) body ....)
123
124or as last variant
125
126* (else body ....)
127
128This one macro replaces in algebraic messages the many accessor
129routines by destructuring the variants via pattern matching. It
130destructures obj of type depending on its variants, i.e.
131matches the variant-key and the argument-list (variant-key (arg ...))
132in sequence and invokes the body .... of the first matching pair.
133The else clause serves as catch-all.
134
135==== define-algebraic-type
136
137<macro>(define-algebraic-type Child Parent .. variant ....)</macro>
138
139where each variant is either of the form
140* (variant-key (a a? ...) ...)
141or with rest arguments
142* (variant-key (a a? ...) ... as as? ...)
143defines a selector routine, Child, which, when called with the
144#:? keyword returns the type predicate, when called with another
145keyword, returns the corresponding message-constructor.
146When Child is called with no argument, it returns information
147on the type.
148Note that rest arguments, as, as well as their checks
149are not parenthesized.
150
151==== define-abstract-type
152
153<macro>(define-abstract-type Child Parent .. variant .... (with clause ....)</macro>
154
155defines a hidden algebraic type with variant .... and exports two
156procedures, the type predicate Child? and a parametrized procedure
157Child, which, when called with key #:? returns the type predicate,
158wenn called with another key argument returns the corresponding
159procedure (Child key) ... , when called without argument returns
160documentation of all those procedures.
161
162All the procedures are specified in each clause .... either as
163
164* ((key (x x? ...) ...) body ....)
165
166or
167
168* ((key (x x? ...) ... xs xs? ...) body ....)
169
170Note that the first list in each clause looks like a variant in the
171algebraic type.
172
173Note also that the exported objects in the with clause have access to the
174hidden algebraic type, which can be processed via algebraic-case
175
176<macro>(define-object-type Child Parent .. state (msg . code) ....)</macro>
177
178where state is either (state ((a a? ...) ...) inv ....) or
179(state ((a a? ...) ... as as? ...) inv ....)
180and code is the body of the procedure to be called in case msg is
181matched.
182Defines a constructor (Child-instance a ...) or
183(Child-instance a ... . as) checked with predicate Child-instance?,
184as well as an algebraic-type Child, which is used to manipulate the
185instance's state.
186The constructor's arguments are checked by a? ... and as?
187respectively.
188
189==== define-object-type
190
191<macro>(define-object-type Child Parent .. state pair ....)</macro>
192
193where state is either
194* (state ((a a? ...) ...) inv ...)
195or
196* (state ((a a? ...) ... as as? ...)
197
198and each pair is a message constructor paired with code
199* ((#:x (x x? ...) ...) xpr ....)
200or
201* ((#:x (x x? ...) ... xs xs? ...) xpr ....)
202
203Here, a, ..., as ... are the instance variables, checked with
204a? ... and as? ... respectively and inv .... is the body of the
205invariant.
206
207Creates an instance constructor, Child-instance, an instance predicate,
208Child-instance?, as well as an algebraic type, Child. An instance,
209child say, is a message dispatcher with state, which dispatches against
210messages created by Child's constructors.
211
212Note that this object model is similar to Oberon's.
213
214=== Dependencies
215
216bindings, checks, symbol-utils
217
218==== Examples
219
220<enscript highlight=scheme>
221
222;; options
223(define-algebraic-type Option
224  (#:none)
225  (#:some (n number?)))
226
227(define (qux opt)
228  (case-variant Option opt
229    (#:none () #f)
230    (#:some (arg) arg)))
231
232(qux ((Option #:some) 5)) ; -> 5
233(qux ((Option #:none))) ; -> #f
234
235;; immutable typed lists
236(define (0<= x) (and (number? x) (not (negative? x))))
237(define-abstract-type List
238  (#:null)
239  (#:cons (first number?) (rest (List #:?)))
240  (with
241    ((#:maker args number?)
242     (let loop ((args args))
243       (if (null? args)
244         ((List #:null))
245         ((List #:cons) (car args)
246                        (loop (cdr args))))))
247    ((#:null? (xs (List #:?)))
248     (case-variant List xs
249       (#:null () #t)
250       (else #f)))
251    ((#:ref (xs (List #:?))
252            (k 0<=))
253     (let loop ((xs xs) (k k))
254       (case-variant List xs
255         (#:null () (error '(List #:ref)))
256         (#:cons (a as) (if (zero? k)
257                          a
258                          (loop as (- k 1)))))))
259    ((#:tail (xs (List #:?))
260             (k 0<=))
261     (let loop ((xs xs) (k k))
262       (case-variant List xs
263         (#:null () xs)
264         (#:cons (a as) (if (zero? k)
265                          xs
266                          (loop as (- k 1)))))))
267    ))
268
269(define as0123 ((List #:maker) 0 1 2 3))
270
271((List #:ref) as0123 2) ; -> 2
272((List #:null?) ((List #:tail) as0123 4)) ; -> #t
273
274;; objects
275(define-object-type Rect
276  (state ((x% (cell-of? number?))
277          (y% (cell-of? number?))
278          (w% (cell-of? number?))
279          (h% (cell-of? number?)))
280    #t)
281  ((#:x) (x%))
282  ((#:y) (y%))
283  ((#:w) (w%))
284  ((#:h) (h%))
285  ((#:x! (x number?)) (x% x))
286  ((#:y! (y number?)) (y% y))
287  ((#:w! (w number?)) (w% w))
288  ((#:h! (h number?)) (h% h))
289  ((#:move! (dx number?) (dy number?))
290   (let ((x (x%)) (y (y%)))
291     (x% (+ dx x))
292     (y% (+ dy y))
293     (list x y)))
294  ((#:scale! (r number?))
295   (let ((w (w%)) (h (h%)))
296     (w% (* r w))
297     (h% (* r h))
298     (list w h)))
299  )
300
301(define rect (Rect-instance (cell 0) (cell 0) (cell 1) (cell 1)))
302
303(define-object-type Square Rect
304  (state ((parent Rect-instance?))
305    (= (parent ((Rect #:w))) (parent ((Rect #:h)))))
306  ((#:parent)  parent)
307  ((#:w! (w number?))
308   (let ((old (parent ((Rect #:w)))))
309     (parent ((Rect #:w!) w))
310     (parent ((Rect #:h!) w))
311     old))
312  ((#:h! (h number?))
313   (let ((old (parent ((Rect #:h)))))
314     (parent ((Rect #:w!) h))
315     (parent ((Rect #:h!) h))
316     old))
317  ((#:scale! (r number?))
318   (let ((old-w (parent ((Rect #:w))))
319         (old-h (parent ((Rect #:h)))))
320     (parent ((Rect #:scale!) r))
321     (list old-w old-h)))
322  )
323
324(define square
325  (Square-instance
326    (Rect-instance (cell 0) (cell 0) (cell 1) (cell 1))))
327
328(square ((Square #:w))) ; -> 1
329(square ((Square #:w!) 50)) ; -> 1
330(square ((Square #:w))) ; -> 50
331(square ((Square #:h))) ; -> 50
332
333(define-object-type Baz
334  (state ((a number?) as number?) #t)
335  ((#:x) a)
336  ((#:xs) as))
337
338(define baz (Baz-instance 0 1 2 3))
339
340(baz ((Baz #:x))) ; -> 0
341(baz ((Baz #:xs))) ; -> '(1 2 3)
342(baz ((Baz #:invariant?))) ;-> #t
343
344</enscript>
345
346== Last update
347
348Mar 01, 2019
349
350== Author
351
352[[/users/juergen-lorenz|Juergen Lorenz]]
353
354== License
355
356 Copyright (c) 2015-2019, Juergen Lorenz
357 All rights reserved.
358
359 Redistribution and use in source and binary forms, with or without
360 modification, are permitted provided that the following conditions are
361 met:
362 
363 Redistributions of source code must retain the above copyright
364 notice, this list of conditions and the following disclaimer.
365 
366 Redistributions in binary form must reproduce the above copyright
367 notice, this list of conditions and the following disclaimer in the
368 documentation and/or other materials provided with the distribution.
369 Neither the name of the author nor the names of its contributors may be
370 used to endorse or promote products derived from this software without
371 specific prior written permission.
372   
373 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
374 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
375 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
376 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
377 HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
378 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
379 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
380 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
381 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
382 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
383 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
384
385== Version History
386; 0.4 : dependency on simple-cells removed and added in test-dependencies
387; 0.3 : dependency on simple-cells added
388; 0.2 : dependency on symbol-utils added
389; 0.1 : initial import
390
391
Note: See TracBrowser for help on using the repository browser.