(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 ©) ;;=> 0 ;; (p ©) ;;=> 1 ;; (p ©)) ;;=> 2 ;; ;; see also ‘seqf which does almost exactly the same thing (def counter ()

(let i -1
  (fn () (++ i))))