(chapter-start 'nydp-core "essential functions for getting anything done") (def iso (x y) (or (eq? x y) (and (pair? x) (pair? y) (eq? (len x) (len y)) (iso (car x) (car y)) (iso (cdr x) (cdr y))))) (def num? (arg) (comment "true if arg is a number") (isa 'number arg)) (def string? (arg) (comment "true if arg is a string") (isa 'string arg)) ;; this is useful sometimes when 'expr can't stand on its own due to lexical ambiguity, most often in string interpolations ;; for example, in "hello ~person, how are you", the parser will try to interpolate the symbol "person," rather than the ;; expected "person". In this case, use "hello ~(just person), how are you" (mac just (expr) expr) (def quotify (arg) `(quote ,arg)) ;; return a function that always returns 'arg, similar to K in SKI calculus (defmemo k (arg) (fn nil arg)) ;; return the length of 'things where 'things may be nil, a string, list or hash ;; length of nil is zero, length of hash is number of keys, length of string ;; is number of characters, length of list is number of direct items - no recursive counting (def len (things) (chapter list-manipulation) (chapter string-manipulation) (chapter hash-manipulation) (if (pair? things) (list-length things) (string? things) (string-length things) (hash? things) (list-length:hash-keys things) things nil 0)) (assign dynamics (hash)) ;; creates a dynamic variable. (mac dynamic (name initial) (let with-mac-name (sym:+ "w/" name) (w/uniq prev `(do (hash-set dynamics ',name t) (mac ,with-mac-name (new-value . body) (w/uniq result `(let ,',prev (hash-get (thread-locals) ',',name) (hash-set (thread-locals) ',',name ,new-value) (returning (do ,@body) (hash-set (thread-locals) ',',name ,',prev))))) ,(if initial `(hash-set (thread-locals) ',name ,initial)) (def ,name () (hash-get (thread-locals) ',name)))))) ;; overrides 'privately defined earlier in documentation manager (dynamic privately) ;; suppress documentation of anything defined in 'body (mac in-private body `(w/privately t ,@body)) ;; a macro wrapper for 'map ;; 'things is a list, 'x is the name of a variable, and 'expr ;; is evaluated and collected for each 'x in 'things ;; usage: (mapx items v (to-string v)) equivalent to (map to-string items) (mac mapx (things x expr) (chapter list-manipulation) `(map (fun (,x) ,expr) ,things)) ;; 't if 'thing is not nil or a list or a hash (def atom? (thing) (chapter nydp-core) (and thing (!pair? thing) (!hash? thing))) (def empty? (things) ; t if it's nil or an empty list, string, or hash ; nil otherwise (chapter list-manipulation) (chapter string-manipulation) (chapter hash-manipulation) (let l (len things) (and l (eq? l 0)))) (def present? (thing) ; t if it's a symbol or number, or a non-empty string, list or hash ; nil otherwise (chapter list-manipulation) (chapter string-manipulation) (chapter hash-manipulation) (!empty? thing)) ;; returns the first non-empty item in 'args ;; mac equivalent of (detect present? args) ;; useful to obtain a non-blank value from a set of variables, for example ;; (%span.name (dp {first} {last} {email} "unknown")) (mac dp args (if args (w/uniq nearg `(let ,nearg ,(car args) (if (empty? ,nearg) (dp ,@(cdr args)) ,nearg))) nil)) ;; returns a function that returns a number sequence. Example: ;; (let c (counter) ;; (p (c)) ;;=> 0 ;; (p (c)) ;;=> 1 ;; (p (c))) ;;=> 2 ;; ;; see also 'seqf which does almost exactly the same thing (def counter () (let i -1 (fn () (++ i))))