nydp 0.4.3 → 0.4.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/lib/lisp/core-010-precompile.nydp +5 -6
  3. data/lib/lisp/core-012-utils.nydp +2 -1
  4. data/lib/lisp/core-015-documentation.nydp +17 -11
  5. data/lib/lisp/core-020-utils.nydp +5 -5
  6. data/lib/lisp/core-030-syntax.nydp +29 -9
  7. data/lib/lisp/core-035-flow-control.nydp +15 -6
  8. data/lib/lisp/core-037-list-utils.nydp +22 -0
  9. data/lib/lisp/core-039-module.nydp +24 -0
  10. data/lib/lisp/core-040-utils.nydp +11 -12
  11. data/lib/lisp/core-041-string-utils.nydp +24 -0
  12. data/lib/lisp/core-042-date-utils.nydp +16 -0
  13. data/lib/lisp/core-043-list-utils.nydp +72 -50
  14. data/lib/lisp/core-080-pretty-print.nydp +50 -17
  15. data/lib/lisp/core-090-hook.nydp +13 -1
  16. data/lib/lisp/core-100-utils.nydp +82 -2
  17. data/lib/lisp/core-110-hash-utils.nydp +38 -0
  18. data/lib/lisp/core-120-settings.nydp +11 -2
  19. data/lib/lisp/core-900-benchmarking.nydp +17 -17
  20. data/lib/lisp/tests/accum-examples.nydp +28 -1
  21. data/lib/lisp/tests/at-syntax-examples.nydp +17 -0
  22. data/lib/lisp/tests/best-examples.nydp +9 -0
  23. data/lib/lisp/tests/builtin-tests.nydp +10 -0
  24. data/lib/lisp/tests/case-examples.nydp +14 -0
  25. data/lib/lisp/tests/date-examples.nydp +54 -1
  26. data/lib/lisp/tests/detect-examples.nydp +12 -0
  27. data/lib/lisp/tests/dp-examples.nydp +24 -0
  28. data/lib/lisp/tests/empty-examples.nydp +1 -1
  29. data/lib/lisp/tests/error-tests.nydp +4 -4
  30. data/lib/lisp/tests/hash-examples.nydp +17 -0
  31. data/lib/lisp/tests/list-grep-examples.nydp +40 -0
  32. data/lib/lisp/tests/list-tests.nydp +39 -0
  33. data/lib/lisp/tests/module-examples.nydp +10 -0
  34. data/lib/lisp/tests/parser-tests.nydp +16 -0
  35. data/lib/lisp/tests/pretty-print-tests.nydp +8 -2
  36. data/lib/lisp/tests/settings-examples.nydp +1 -1
  37. data/lib/lisp/tests/string-tests.nydp +48 -0
  38. data/lib/lisp/tests/syntax-tests.nydp +5 -1
  39. data/lib/nydp.rb +6 -3
  40. data/lib/nydp/assignment.rb +10 -3
  41. data/lib/nydp/builtin.rb +1 -1
  42. data/lib/nydp/builtin/abs.rb +8 -0
  43. data/lib/nydp/builtin/date.rb +9 -0
  44. data/lib/nydp/builtin/error.rb +1 -1
  45. data/lib/nydp/builtin/hash.rb +11 -1
  46. data/lib/nydp/builtin/ruby_wrap.rb +69 -0
  47. data/lib/nydp/builtin/string_pad_left.rb +7 -0
  48. data/lib/nydp/builtin/string_pad_right.rb +7 -0
  49. data/lib/nydp/builtin/type_of.rb +9 -6
  50. data/lib/nydp/closure.rb +0 -3
  51. data/lib/nydp/cond.rb +23 -1
  52. data/lib/nydp/context_symbol.rb +14 -6
  53. data/lib/nydp/core.rb +33 -29
  54. data/lib/nydp/core_ext.rb +5 -4
  55. data/lib/nydp/date.rb +17 -17
  56. data/lib/nydp/function_invocation.rb +33 -25
  57. data/lib/nydp/helper.rb +12 -2
  58. data/lib/nydp/interpreted_function.rb +68 -40
  59. data/lib/nydp/literal.rb +1 -1
  60. data/lib/nydp/pair.rb +13 -2
  61. data/lib/nydp/parser.rb +3 -0
  62. data/lib/nydp/symbol_lookup.rb +7 -7
  63. data/lib/nydp/version.rb +1 -1
  64. data/nydp.gemspec +2 -4
  65. data/spec/date_spec.rb +79 -0
  66. data/spec/parser_spec.rb +11 -0
  67. metadata +15 -36
  68. data/lib/nydp/builtin/car.rb +0 -7
  69. data/lib/nydp/builtin/cdr.rb +0 -7
  70. data/lib/nydp/builtin/cons.rb +0 -9
@@ -1,13 +1,39 @@
1
+
2
+ ;;
3
+ ;; problem: work out where a starting column of a form on its starting line, need to add
4
+ ;; this amount to its indent if it is broken
5
+ ;;
6
+ ;; TODO:
7
+ ;;
8
+ ;; alternative approach: given a form <expr>, ask <expr> recursively
9
+ ;; to provide the following:
10
+ ;;
11
+ ;; { inline: (... <sub-expr> <sub-expr> ...)
12
+ ;; broken: (... <newline " "> <sub-expr> <newline " "> <sub-expr> ...) }
13
+ ;;
14
+ ;; printer returns <inline> if acceptable, otherwise produces <broken>, recursively deciding on <inline>
15
+ ;; for each <sub-expr>
16
+ ;;
17
+ ;; each <newline " "> carries the amount of indent required for the containing form, needs to be added to
18
+ ;; the amount of indent required for outer forms
19
+ ;;
20
+ ;;
21
+ ;;
22
+ ;; also TODO:
23
+ ;;
24
+ ;; use (module pp ...) and remove all those prefixes...
25
+ ;;
26
+
1
27
  (assign pp/special-forms (hash))
2
28
  (assign pp/syntaxes (hash))
3
29
  (assign pp/newline (uniq 'newline))
4
30
  (assign pp/newline/noi (uniq 'newline/noi))
5
31
 
32
+ ;; (eq? char "\n") "\\n"
6
33
  (def pp/esc-ch (char)
7
34
  (if (eq? char "\"") "\\\""
8
35
  (eq? char "\~") "\\\~"
9
36
  (eq? char "\\") "\\\\"
10
- (eq? char "\n") "\\n"
11
37
  char))
12
38
 
13
39
  (def pp/esc-str-literal (txt)
@@ -35,11 +61,11 @@
35
61
  (isa 'hash thing) "{ ~(joinstr " " (pp/kv thing)) }"
36
62
  (inspect thing)))
37
63
 
64
+ ;; define a pretty-printer function for forms beginning with the
65
+ ;; given name. 'args are usually (form indent), form being the
66
+ ;; complete form for pretty-printing, and indent being the current
67
+ ;; indent level.
38
68
  (mac pp/def (name args . body)
39
- ; define a pretty-printer function for forms beginning with the
40
- ; given name. 'args are usually (form indent), form being the
41
- ; complete form for pretty-printing, and indent being the current
42
- ; indent level.
43
69
  `(do (hash-set pp/special-forms ',name
44
70
  (fun ,args ,@body))
45
71
  (dox-add-doc ',name
@@ -48,6 +74,7 @@
48
74
  ',args
49
75
  '(pp/def ,name ,args ,@body))))
50
76
 
77
+
51
78
  (pp/def string-pieces (pp form indent) (pp/string-pieces pp (cdr form)))
52
79
  (pp/def quasiquote (pp form indent) "`~(pp (cadr form) (cons "" indent))" )
53
80
  (pp/def quote (pp form indent) "'~(pp (cadr form) (cons "" indent))" )
@@ -55,7 +82,12 @@
55
82
  (pp/def unquote-splicing (pp form indent) ",@~(pp (cadr form) (cons " " indent))")
56
83
  (pp/def comment (pp form indent) "; ~(cadr form)\n")
57
84
  (pp/def prefix-list (pp form indent) "~(cadr form)~(pp (caddr form))")
58
- (pp/def brace-list (pp form indent) "{ ~(joinstr " " (map λe(pprint e (cons " " indent)) (cdr form))) }")
85
+
86
+
87
+ (def pp/brace-list-pair (pp (k v) indent) "~k ~(pp v indent)")
88
+
89
+ (pp/def brace-list (pp form indent)
90
+ "{ ~(joinstr " " (map λe(pprint e (cons " " indent)) (intersperse-splicing pp/newline (pairs:cdr form)))) }")
59
91
 
60
92
  (def pp/unsyntax (form)
61
93
  (if (pair? form)
@@ -65,15 +97,16 @@
65
97
  (map pp/unsyntax form)))
66
98
  form))
67
99
 
68
- (hash-set pp/syntaxes 'percent-syntax "%")
69
- (hash-set pp/syntaxes 'colon-syntax ":")
70
- (hash-set pp/syntaxes 'dot-syntax ".")
71
- (hash-set pp/syntaxes 'bang-syntax "!")
72
- (hash-set pp/syntaxes 'ampersand-syntax "&")
73
- (hash-set pp/syntaxes 'dollar-syntax "$")
74
- (hash-set pp/syntaxes 'colon-colon-syntax "::")
75
- (hash-set pp/syntaxes 'arrow-syntax "->")
76
- (hash-set pp/syntaxes 'rocket-syntax "=>" )
100
+ (hash-set pp/syntaxes 'percent-syntax "%" )
101
+ (hash-set pp/syntaxes 'colon-syntax ":" )
102
+ (hash-set pp/syntaxes 'dot-syntax "." )
103
+ (hash-set pp/syntaxes 'bang-syntax "!" )
104
+ (hash-set pp/syntaxes 'ampersand-syntax "&" )
105
+ (hash-set pp/syntaxes 'dollar-syntax "$" )
106
+ (hash-set pp/syntaxes 'colon-colon-syntax "::" )
107
+ (hash-set pp/syntaxes 'arrow-syntax "->" )
108
+ (hash-set pp/syntaxes 'rocket-syntax "=>" )
109
+ (hash-set pp/syntaxes 'at-syntax "@" )
77
110
 
78
111
  (def pp/dotify (form)
79
112
  (if (pair? form)
@@ -160,9 +193,9 @@
160
193
  (pprint (pp/break-pair form) indent)
161
194
  (pp/literal form indent)))
162
195
 
196
+ ;; better than (def pp (form) (inspect form))
163
197
  (def pp (form) (pp/cleanup:pp/printer (pp/dotify:pp/unsyntax form) nil))
164
- ;; (def pp (form) (inspect form))
165
198
 
199
+ ;; use the pretty-printer to elegantly display the given source code
166
200
  (def dox-show-src (src)
167
- ; use the pretty-printer to elegantly display the given source code
168
201
  (pp src))
@@ -43,7 +43,19 @@
43
43
  ; same as (add-hook 'transaction (fn (account amount) (update account total (+ account.total amount))))
44
44
  ;
45
45
  (mac on (event args . body)
46
- `(add-hook ',event (fn ,args ,@body)))
46
+ (let hookfn (if (isa 'symbol (car body))
47
+ (car body)
48
+ `(fn ,args ,@body))
49
+ (w/uniq dox-item
50
+ `(let ,dox-item (car:dox-lookup ',event)
51
+ (if (no ,dox-item) (error "unknown hook ~(just ',event)"))
52
+ (add-hook ',event ,hookfn)
53
+ (hash-cons ,dox-item 'hooks
54
+ { src ',hookfn
55
+ args ',args
56
+ chapter (chapter-current)
57
+ file this-script
58
+ plugin this-plugin })))))
47
59
 
48
60
  (let super warnings/new
49
61
  (def warnings/new (kind . info)
@@ -21,6 +21,12 @@
21
21
  (def safe-sort-by (f instead things)
22
22
  (sort-by λi(or (f i) instead) things))
23
23
 
24
+ ;; takes a function f, returns a new function that takes a list and sorts the list by 'f
25
+ (def sort-by-f (f) (curry1 sort-by f))
26
+
27
+ ;; takes a function f, returns a new function that takes a list and sorts the list by 'f
28
+ (def safe-sort-by-f (f instead) (curry1 safe-sort-by f instead))
29
+
24
30
  (def mapreduce (fmap freduce things)
25
31
  ; same as (reduce freduce (map fmap things))
26
32
  ; returns the resulting list
@@ -47,9 +53,9 @@
47
53
  ; return a list containing all the elements of 'things, but with no duplicates
48
54
  (def uniqify (things) (reject (seen?) things))
49
55
 
56
+ ;; return a hash of 'things keyed by (f thing) for
57
+ ;; each thing in 'things
50
58
  (def group-by (f things)
51
- ; return a hash of 'things keyed by (f thing) for
52
- ; each thing in 'things
53
59
  (returnlet hsh {}
54
60
  (each thing things
55
61
  (hash-cons hsh (f thing) thing))))
@@ -64,6 +70,14 @@
64
70
  (let mi (m2i anchor)
65
71
  (map λm(i2m (+ mi m)) mm))))
66
72
 
73
+ ;; each call to the name 'accfn-name with an arg will append the arg to the end of a list.
74
+ ;; This form returns the resulting list.
75
+ ;; Example (collect first names from a list of people)
76
+ ;;
77
+ ;; (accum a (each person people (a person.firstname)))
78
+ ;;
79
+ ;; will return (Alice Bob Carol Declan Eliza Fionn)
80
+ ;;
67
81
  (mac accum (accfn-name . body)
68
82
  (w/uniq (things last-cons)
69
83
  `(with (,last-cons (cons) ,things nil)
@@ -72,6 +86,17 @@
72
86
  ,@body
73
87
  (cdr ,things)))))
74
88
 
89
+ ;; like 'accum, except 'accfn-name expects 2 args, a key and a value
90
+ ;; value is hash-consed onto key in an internally-maintained hash
91
+ ;; the form returns the resulting hash
92
+ ;; values are in reverse order
93
+ (mac accum-hash (accfn-name . body)
94
+ (w/uniq (hsh)
95
+ `(with (,hsh (hash))
96
+ (let ,accfn-name (fn (k a) (hash-cons ,hsh k a))
97
+ ,@body
98
+ ,hsh))))
99
+
75
100
  ; return a list containing the range of elements starting with 'start,
76
101
  ; up to but not including 'stop
77
102
  (def range (start stop)
@@ -160,3 +185,58 @@
160
185
  (acc (car xs))
161
186
  (self (cdr xs))))
162
187
  things)))
188
+
189
+ ;; returns a list containing 'existing items, that has at least 'minimum items, building new items if necessary
190
+ ;;
191
+ ;; useful if you want to show, for example, two parent fields, but you don't know in advance whether there
192
+ ;; are zero, one, two, or more parents already present
193
+ ;;
194
+ ;; existing: the existing list
195
+ ;; buildf: a zero-argument function to build a new item
196
+ ;; minimum: the minimum number of items in the returned list.
197
+ ;;
198
+ (def list/fill (existing buildf minimum)
199
+ (let missing (- minimum (len existing))
200
+ (if (> missing 0)
201
+ (+ existing (map buildf (range 0 missing)))
202
+ existing)))
203
+
204
+ ;; recursively search the given form for forms matching 'matcher
205
+ ;; matcher is a function which returns nil for non-match, anything else for match
206
+ ;; returns the list of non-nil objects returned by 'matcher
207
+ ;; 'matcher will be called with the entire form, and if the form is a list, with each element of the form, recursively
208
+ (def list/grep (matcher form)
209
+ (accum matches
210
+ (let maybe λi(if (matcher i) (matches i))
211
+ (list/traverse maybe maybe form))))
212
+
213
+ ;; recursively seeks forms in 'form whose car is 'symbol
214
+ (def list/seek-cars (symbol form)
215
+ (list/grep λf(caris symbol f) form))
216
+
217
+ ;; helper function for 'case macro
218
+ (def case/make-conds (test varname conds acc)
219
+ (if conds
220
+ (let (cnd expr) (car conds)
221
+ (if (eq? cnd 'else)
222
+ (acc expr)
223
+ (do (acc `(,test ,varname ,cnd))
224
+ (acc expr)
225
+ (case/make-conds test
226
+ varname
227
+ (cdr conds)
228
+ acc))))))
229
+
230
+ ;; usage: (case eq? person.name
231
+ ;; "conan" (greet person)
232
+ ;; "egg" (delete person)
233
+ ;; "bach" (play person)
234
+ ;; else (interrogate person))
235
+ (mac case (test what . conditions)
236
+ (w/uniq caseval
237
+ `(let ,caseval ,what
238
+ (if ,@(accum a
239
+ (case/make-conds test
240
+ caseval
241
+ (pairs conditions)
242
+ a))))))
@@ -15,9 +15,47 @@
15
15
  (map-with-index λki(f k (hash-get h k) i)
16
16
  ((or pre x1) (hash-keys h))))
17
17
 
18
+ ;; returns a new hash with the same keys as the given hash, with each value transformed by
19
+ ;; the given function 'f
20
+ ;; 'f takes three arguments:
21
+ ;; k, the key
22
+ ;; v, the value
23
+ ;; i, the index
24
+ ;;
25
+ (def hash-transform-values (f h pre)
26
+ (returnlet newh {}
27
+ (map-hash λkvi(hash-set newh k (f k v i)))))
28
+
29
+
18
30
  ;; Return a new hash where keys are (map f things) and values are the corresponding things.
19
31
  ;; No attempt is made to avoid clobbering items. Use 'group-by if there are duplicate keys.
20
32
  (def hashify (f things)
21
33
  (returnlet hsh {}
22
34
  (each thing things
23
35
  (hash-set hsh (f thing) thing))))
36
+
37
+ ;; like 'group-by, except 'f returns multiple items, each of which
38
+ ;; is used to key the thing in question
39
+ (def subgroup-by (f things)
40
+ (returnlet hsh {}
41
+ (each thing things
42
+ (each k (f thing)
43
+ (hash-cons hsh k thing)))))
44
+
45
+ ;; return a new hash containing all the values of the given
46
+ ;; hash, but with each corresponding key 'k replaced by (f k)
47
+ (def hash-replace-keys (f hsh)
48
+ (returnlet newh {}
49
+ (each k (hash-keys hsh)
50
+ (hash-set newh (f k) (hash-get hsh k)))))
51
+
52
+ ;; repeatedly assigns an element of hash-keys of 'things to 'kvar,
53
+ ;; assign the corresponding value to 'vvar
54
+ ;; and executes 'body for each key-value pair
55
+ ;; return value of form is whatever the last line of 'body returns
56
+ (mac hash-each (kvar vvar things . body)
57
+ (w/uniq xs
58
+ `(let ,xs ,things
59
+ (each ,kvar (hash-keys ,xs)
60
+ (let ,vvar (hash-get ,xs ,kvar)
61
+ ,@body)))))
@@ -1,12 +1,16 @@
1
1
  (chapter-start 'settings "Utilities for managing settings")
2
2
 
3
3
  (assign settings {})
4
+ (assign initial-settings {})
4
5
 
5
6
  ; convert expr to a function that returns the expr, unless expr is a symbol in which case we assume it already refers to a fn
6
7
  (def settings/fn (expr)
7
- (if (sym? expr) expr
8
+ (if (sym? expr) expr
8
9
  (or (atom? expr) (no expr)) `(k ,expr)
9
- `(fn (_) ,expr)))
10
+ (hash? expr) `(k ',expr)
11
+ (caris 'quote expr) `(k ,expr)
12
+ (caris 'brace-list expr) `(k ,expr)
13
+ `(fn (_) ,expr)))
10
14
 
11
15
  ; update value of setting 'name
12
16
  (mac set-setting (name value)
@@ -15,6 +19,10 @@
15
19
  { plugin this-plugin script this-script value ',value })
16
20
  (hash-set settings ',(sym name) ,(settings/fn value))))
17
21
 
22
+ ; update value of setting 'name
23
+ (mac reset-setting (name)
24
+ `(set-setting ,name ,(hash-get initial-settings (sym name))))
25
+
18
26
  (mac def-setting (name initial)
19
27
  ; define a setting in the given 'context with a 'name and an 'initial value, with a 'doc to explain it
20
28
  ; if value is a function, it is invoked with 'context and 'name to retrieve its value
@@ -27,6 +35,7 @@
27
35
  '(def-setting ,name ,initial)
28
36
  '(,(sym "settings/~context"))
29
37
  { setting { default ',initial context ',context name ',name } })
38
+ (hash-set initial-settings ',(sym name) ,initial)
30
39
  (set-setting ,(sym name) ,initial))))
31
40
 
32
41
  ; get the value of the given setting. Raises an error if the setting is unknown
@@ -184,24 +184,20 @@
184
184
  ;; (z 0) (z 1) (z 2) (z 3) (z 4) (z 5) (z 6) (z 7) (z 8) (z 9)))
185
185
 
186
186
  (in-private
187
- (def bm-j ()
188
- (j "abc" '(d e f (g h i)) (list "jk" "lm")))
187
+ (def bm-no-closures ()
188
+ (list λ(+ 1 2)
189
+ λ(+ 1 2)
190
+ λ(+ 1 2)
191
+ λ(+ 1 2)
192
+ λ(+ 1 2)
193
+ λ(+ 1 2)
194
+ λ(+ 1 2)
195
+ λ(+ 1 2)
196
+ λ(+ 1 2)
197
+ λ(+ 1 2)))
189
198
 
190
- (def bm-or-lex-lex-lex (a b c) (or a b c))
191
- (def bm-faster-or ()
192
- (bm-or-lex-lex-lex 1 2 3)
193
- (bm-or-lex-lex-lex nil 2 3))
194
-
195
- (def build-mapsum-data (count data)
196
- (if (> count 0)
197
- (build-mapsum-data (- count 1)
198
- (cons { mappit (rand 10) }
199
- data))
200
- data))
201
-
202
- (let mapsum-data (build-mapsum-data 1000)
203
- (def bm-mapsum () (mapsum &mappit mapsum-data))
204
- (def bm-mapreduce () (mapreduce &mappit + mapsum-data 0))))
199
+ (def bm-cons () (cons 'a 'b))
200
+ (def bm-type-of () (type-of 'a)))
205
201
 
206
202
 
207
203
 
@@ -223,8 +219,12 @@
223
219
  (p "================================================\n")
224
220
  "~desc : total ~(just times), average ~(/ times repeats) per run"))
225
221
 
222
+
223
+
226
224
  (def rbs (name)
227
225
  (let summary nil
226
+ (push (bm "no-closures " bm-no-closures 10 20000) summary)
227
+ ;; (push (bm "type-of " bm-type-of 10 20000) summary)
228
228
  ;; (push (bm "accum " bm-acc 10 500) summary)
229
229
  ;; (push (bm "accum " bm-facc 10 500) summary)
230
230
  ;; (push (bm "mapsum " bm-mapsum 10 100) summary)
@@ -4,4 +4,31 @@
4
4
  (a 1)
5
5
  (a 2)
6
6
  (a 3))
7
- (1 2 3)))
7
+ (1 2 3))
8
+
9
+ ("accum function returns the accumulated object in each case"
10
+ (let watcher nil
11
+ (let accumulated (accum b
12
+ (= watcher (cons (b 1) watcher))
13
+ (= watcher (cons (b 2) watcher))
14
+ (= watcher (cons (b 3) watcher)))
15
+ (list 'watcher watcher 'accumulated accumulated)))
16
+ (watcher (3 2 1)
17
+ accumulated (1 2 3))))
18
+
19
+ (examples-for accum-hash
20
+ ("accumulate the values passed to a given function under the given key, return the resulting hash"
21
+ (let h
22
+ (accum-hash hi
23
+ (hi 'a 1)
24
+ (hi 'a 2)
25
+ (hi 'b 42)
26
+ (hi 'b 43)
27
+ (hi 'a 3)
28
+ (hi 'b 44)
29
+ (hi 'c 'x)
30
+ (hi 'a 4)
31
+ (hi 'c 'y)
32
+ (hi 'c 'z))
33
+ (list h.a h.b h.c))
34
+ ((4 3 2 1) (44 43 42) (z y x))))
@@ -0,0 +1,17 @@
1
+ (examples-for at-syntax
2
+ ("at-symbol as argument"
3
+ (let @ {}
4
+ (= @foo 1)
5
+ (= @bar 2)
6
+ (list @foo @bar))
7
+ (1 2))
8
+
9
+ ("at-syntax assignment"
10
+ (pre-compile '(= @a 42))
11
+ (hash-set @ 'a 42))
12
+
13
+ ("mixed at-syntax and dot-syntax assignment"
14
+ (pre-compile '(= @a.b 42))
15
+ (hash-set (hash-get @ 'a) 'b 42)))
16
+
17
+ ;; (let @ {} 123)
@@ -19,6 +19,15 @@
19
19
  (best > '(c g d o a p b m e g a z m))
20
20
  z)
21
21
 
22
+ ("finds object with max size"
23
+ (to-string:best (map-compare-f > &size)
24
+ (list { i 0 size 3 }
25
+ { i 1 size 1 }
26
+ { i 2 size 7 }
27
+ { i 3 size 4 }
28
+ { i 4 size 5 }))
29
+ "{i=>2, size=>7}")
30
+
22
31
  ("finds maximum of list of numbers"
23
32
  (best > '(3 5 4 7 8 2))
24
33
  8))