nydp 0.4.3 → 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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))