;;;; standard library ;;; void (def (void . rest) "Return the constant `#<void>` while ignoring any arguments. `#<void>` is mainly used when a function has side effects but does not produce any meaningful value to return, so even though `T` or `NIL` could be returned instead, in case of `#<void>` alone, REPL will not print it." :doc-group misc :doc-see void? #.(void)) (def (void? v) "Return `T` if `v` is `#<void>`, `NIL` otherwise." :doc-group type :doc-group misc :doc-see void (eq? v #.(void))) ;;; syntax environment (unless (bound? '*syntax-environment*) (def *syntax-environment* "Table containing macro definitions. The keys are macro names, the values are their application functions." :doc-group syntax :doc-see get-syntax :doc-see set-syntax! (table))) (def (set-syntax! sym fn) "Associate a macro name with its application function." :doc-group syntax :doc-see get-syntax (put! *syntax-environment* sym fn)) (def (get-syntax sym) "Return a macro application function based on its name, or `NIL` if it's not defined." :doc-group syntax :doc-see set-syntax! (get *syntax-environment* sym NIL)) ;;; props ;; This is implemented in a slightly different fashion as expected:;;;; *properties* : key → { symbol → value };;;; The assumption here is that keys will most likely be the same across multiple symbols;; so it makes more sense to reduce the number of subtables for the *properties* table.(unless (bound? '*properties*) (def *properties* "All properties of symbols recorded with `putprop` are recorded in this table." :doc-group prop (table))) (def (putprop symbol key val) "Associate a property value with the symbol." :doc-group prop :doc-see getprop (let ((kt (get *properties* key NIL))) (unless kt (let ((ta (table))) (put! *properties* key ta) (set! kt ta))) (put! kt symbol val) val)) (def (getprop symbol key (def NIL def-supplied?)) "Return a property value associated with the symbol or `def` if missing. If the default value is not supplied and the property is missing, an exception will be thrown." :doc-group prop :doc-see putprop (let ((kt (get *properties* key NIL))) (if def-supplied? (or (and kt (get kt symbol def)) def) (if kt (get kt symbol) (raise (list 'key-error key)))))) (def (remprop symbol key) "Remove a property value associated with the symbol." :doc-group prop (void (let ((kt (get *properties* key NIL))) (and kt (has? kt symbol) (del! kt symbol))))) ;;; documentation (def (separate-doc-from-body body (doc NIL)) "Take a list of terms and return a pair `(doc . body)`, where the first element contains a list of documentation-related terms, and the second contains the rest of the terms." :doc-group doc (def (doc? kw) (<= :doc-a kw :doc-z)) (let {[hd (car body)] [tl (cdr body)]} (cond [(and (str? hd) (not doc) tl) (separate-doc-from-body tl (cons hd doc))] [(and doc (doc? hd)) (separate-doc-from-body (cdr tl) (cons (cons hd (car tl)) doc))] [else (cons (reverse doc) body)]))) (def (sym-set-doc symbol doc-seq . formals-list) "Set the documentation for the symbol." :doc-group doc (def (formals-clean fs) (when (atom? fs) (return fs)) (let ((f (car fs))) (cons (if (and (cons? f) (length> f 2)) (subseq f 0 2) f) (formals-clean (cdr fs))))) (let* {[doc-only (str? doc-seq)] [doc (if doc-only doc-seq (car doc-seq))] [extra (if doc-only NIL (cdr doc-seq))] [formals-list (map formals-clean formals-list)]} (when (and (bound? 'str-join) doc) (let* {[lines (str-split doc "\n")] [hd (car lines)] [tl (cdr lines)] [snd (any (λ (s) (and (> (length s) 0) (rune-whitespace? (str-rune s 0)) s)) tl)] [indent (and snd (- (length snd) (length (str-trim snd))))] [trimmed (and snd (map (λ (s) (if (<= indent (length s)) (str-sub s indent) s)) tl))] [final (str-join (cons hd trimmed) "\n")]} (putprop symbol '*doc* final) (when extra (putprop symbol '*doc-extra* extra)))) (when (cons? formals-list) (putprop symbol '*formals-list* (delete-duplicates [append (getprop symbol '*formals-list* NIL) formals-list]))) #.(void))) (def (help-print-header term sigs (:kind NIL) (:lpad "")) "Format and print signature(s) of the term for `(help term)` output." :doc-group doc (def (print-type e) (set! print-type void) (princ " ;; [" [cond ((not (sym? e)) (type-of e)) ((and (sym? e) (bound? e)) (type-of (top-level-value term))) ((get-syntax e) "macro") (else "any")] "]")) (if sigs (for-each (λ (sig) (princ lpad) (print (cons term sig)) (print-type term) (newline)) sigs) (princ lpad) (if kind (begin (princ (caddr term)) (print-type "doc group")) (print term) (print-type term)) (newline)) (newline)) (defmacro (help topic (:print-header help-print-header) . rest) "Display documentation for a specific term or group of terms, if available. An optional symbol `group` is used to query for documentation on a group instead of a single term. All available documentation groups can be displayed with `(help groups)`. Asterisk can be added to the beginning and/or end of the term in order to list the matching terms defined in the current environment. This can be useful to recall a function's name. Examples: (help str?) ; show documentation for str? (help groups) ; show documentation groups (help type group) ; list items for dealing with types (help group type) ; same as ^ (help str->*) ; find functions converting from strings (help *->str) ; find functions converting to strings (help *num*) ; find anything related to numbers" :doc-group doc (let* {[term (if (eq? topic 'group) (car rest) topic)] [kind (if (eq? topic term) (car rest) topic)] [doc-extra-term (and kind (cons (sym ":doc-" kind) term))] [docterm (if kind (list 'doc kind term) term)] [doc (getprop docterm '*doc* NIL)] [formals-list (getprop docterm '*formals-list* NIL)] [term-bound (and (sym? term) (bound? term))]} (def (environment-find-matching) (let* {[s (str term)] [ts (eq? 0 (str-find s "*"))] ; starts with [s (or (and ts (str-sub s 1)) s)] [ei (1- (length s))] [te (eq? (str-find s "*") ei)] [s (or (and te (str-sub s 0 ei)) s)] [slen (length s)] [matches? (λ (term) (let* {[name (str term)] [i (str-find name s)] [nlen (and i (length name))]} (and i (or ts (= 0 i)) (or te (= nlen (+ i slen))))))] [matching (nconc (filter matches? (environment)) (filter matches? (table-keys *syntax-environment*)))]} (when matching (for-each (λ (term) (princ term) (newline)) (sort matching <))))) (def (print-sig term sigs lpad) (if sigs (for-each (λ (sig) (newline) (princ lpad) (princ (cons term sig))) sigs) (newline) (princ lpad) (princ term))) (def (first-line s) (str-sub s 0 (str-find s "\n"))) (def (doc-group? k) (and (cons? k) (eq? (car k) 'doc) (eq? (cadr k) 'group))) (def (doc-extra-term? k) (and (atom? k) (member doc-extra-term (getprop k '*doc-extra* NIL)))) (def (table-keys-filter-sort tbl pred) (sort (table-fold (λ (k _ z) (if (pred k) (cons k z) z)) NIL tbl) <)) (if (eq? term 'groups) (for-each (λ (k) (princ (str-rpad (str (caddr k)) 10) (first-line (getprop k '*doc* NIL))) (newline)) (table-keys-filter-sort (get *properties* '*doc*) doc-group?)) (if (or doc formals-list) (begin (print-header docterm formals-list :kind kind) (let* {[extra (getprop docterm '*doc-extra* NIL)] [fmt (filter (λ (v) (eq? (car v) :doc-fmt)) extra)] [see (filter (λ (v) (eq? (car v) :doc-see)) extra)]} (when doc (princ (foldl (λ (fmt doc) ((cdr fmt) doc)) doc fmt)) (newline)) (when see (newline) (princ "See also:") (newline) (for-each (λ (v) (print-sig (cdr v) (getprop (cdr v) '*formals-list* NIL) " ")) see) (newline))) (when kind (newline) (princ "Members:") (newline) (for-each (λ (k) (print-sig k (getprop k '*formals-list* NIL) " ")) (table-keys-filter-sort (get *properties* '*doc*) doc-extra-term?)) (newline)) #.(void)) (unless (and (not term-bound) (environment-find-matching)) (princ "no help for " (if kind (str kind " ") "") term) (when (and (not kind) (sym? term) (not term-bound)) (princ " (undefined)")) (newline)))) (void))) ;;; standard procedures (def (member item lst) "Return the tail of a list beginning with the item, or `NIL` otherwise. List elements are compared to the `item` using `equal?`. Examples: (member 1 '(3 2 1 0)) ; ↳ (1 0) (member 1 '(2 3)) ; ↳ NIL" :doc-group list :doc-see memq :doc-see memv (cond ((equal? (car lst) item) lst) (lst (member item (cdr lst))))) (def (memv item lst) "Return the tail of a list beginning with the item, or `NIL` otherwise. List elements are compared to the `item` using `eqv?`." :doc-group list :doc-see member :doc-see memq (cond ((eqv? (car lst) item) lst) (lst (memv item (cdr lst))))) (def (assoc-list . kvs) "Construct an association list from the arguments. Every two arguments are expected to be a key and a value associated with that key. Examples: (assoc-list 'a 0 'b 1) ; ↳ ((a . 0) (b . 1))" :doc-group list :doc-see assoc (let ((s (cdr kvs))) (when (cons? s) (cons (cons (car kvs) (car s)) (apply assoc-list (cdr s)))))) (def (assoc key lst) "Return a pair of a matching key and the associated value, or `NIL` if none matched. Keys are compared using `equal?`. Examples: (def L (assoc-list 'a 0 'b 1)) (assoc 'b L) ; ↳ (b . 1) (assoc 'c L) ; ↳ NIL" :doc-group list :doc-see assoc-list :doc-see assq :doc-see assv (cond ((equal? (caar lst) key) (car lst)) (lst (assoc key (cdr lst))))) (def (assv key lst) "Return a pair of a matching key and the associated value, or `NIL` if none matched. Keys are compared using `eqv?`." :doc-group list :doc-see assoc :doc-see assq (cond ((eqv? (caar lst) key) (car lst)) (lst (assv key (cdr lst))))) (doc-group compare "Comparison operators.") (def (> v . rest) "Return `T` if the arguments are in strictly decreasing order (previous one is greater than the next one)." :doc-group compare (let loop ((v v) (rest rest)) (or (not rest) (and (< (car rest) v) (loop (car rest) (cdr rest))))))(defmacro (> v . rest) `(< ,.(reverse rest) ,v)) (def (<= v . rest) "Return `T` if the arguments are in non-decreasing order (previous one is less than or equal to the next one)." :doc-group compare (let loop ((v v) (rest rest)) (or (not rest) (unless (or (< (car rest) v) (nan? v)) (loop (car rest) (cdr rest)))))) (def (>= v . rest) "Return `T` if the arguments are in non-increasing order (previous one is greater than or equal to the next one)." :doc-group compare (let loop ((v v) (rest rest)) (or (not rest) (unless (or (< v (car rest)) (nan? v)) (loop (car rest) (cdr rest)))))) (doc-group number "Operations on numbers, mathematical constants.") (def (negative? n) "Return `T` if `n` is a negative number. Shorthand for `(< n 0)`." :doc-group number :doc-group compare (< n 0)) (def (zero? n) "Return `T` if `n` is zero. Shorthand for `(= n 0)`." :doc-group number :doc-group compare (= n 0)) (def (positive? n) "Return `T` if `n` is greater than zero. Shorthand for `(> n 0)`." :doc-group number :doc-group compare (< 0 n)) (def (even? n) "Return `T` if `n` is an even integer, `NIL` otherwise." :doc-group number :doc-see odd? (= (logand n 1) 0)) (def (odd? n) "Return `T` if `n` is an odd integer, `NIL` otherwise." :doc-group number :doc-see even? (not (even? n))) (def (1+ n) "Equivalent to `(+ n 1)` - increment by one." :doc-group number :doc-see 1- (+ n 1)) (def (1- n) "Equivalent to `(- n 1)` - decrement by one." :doc-group number :doc-see 1+ (- n 1)) (def (div a n) "Return the quotient of the Euclidean division `a/n`. Examples: (div 10 3) ; ↳ 3 (div -10 3) ; ↳ -4 (div -10 -3) ; ↳ 4 (div 10 -3) ; ↳ -3" :doc-group number :doc-see mod :doc-see div0 (+ (div0 a n) (or (and (< a 0) (or (and (< n 0) 1) -1)) 0))) (def (mod a n) "Return the remainder of the Euclidean division `a/n`. Examples: (mod 10 3) ; ↳ 1 (mod -10 3) ; ↳ 2 (mod -10 -3) ; ↳ 2 (mod 10 -3) ; ↳ 1" :doc-group number :doc-see div :doc-see mod0 (- a (* (div a n) n))) (def (mod0 a n) "Return the remainder of the truncated division `a/n`. Examples: (mod0 10 3) ; ↳ 1 (mod0 -10 3) ; ↳ -1 Lines 1–500 of 3373. Load more
;;;; standard library ;;; void (def (void . rest) "Return the constant `#<void>` while ignoring any arguments. `#<void>` is mainly used when a function has side effects but does not produce any meaningful value to return, so even though `T` or `NIL` could be returned instead, in case of `#<void>` alone, REPL will not print it." :doc-group misc :doc-see void? #.(void)) (def (void? v) "Return `T` if `v` is `#<void>`, `NIL` otherwise." :doc-group type :doc-group misc :doc-see void (eq? v #.(void))) ;;; syntax environment (unless (bound? '*syntax-environment*) (def *syntax-environment* "Table containing macro definitions. The keys are macro names, the values are their application functions." :doc-group syntax :doc-see get-syntax :doc-see set-syntax! (table))) (def (set-syntax! sym fn) "Associate a macro name with its application function." :doc-group syntax :doc-see get-syntax (put! *syntax-environment* sym fn)) (def (get-syntax sym) "Return a macro application function based on its name, or `NIL` if it's not defined." :doc-group syntax :doc-see set-syntax! (get *syntax-environment* sym NIL)) ;;; props ;; This is implemented in a slightly different fashion as expected: ;; ;; *properties* : key → { symbol → value } ;; ;; The assumption here is that keys will most likely be the same across multiple symbols ;; so it makes more sense to reduce the number of subtables for the *properties* table. (unless (bound? '*properties*) (def *properties* "All properties of symbols recorded with `putprop` are recorded in this table." :doc-group prop (table))) (def (putprop symbol key val) "Associate a property value with the symbol." :doc-group prop :doc-see getprop (let ((kt (get *properties* key NIL))) (unless kt (let ((ta (table))) (put! *properties* key ta) (set! kt ta))) (put! kt symbol val) val)) (def (getprop symbol key (def NIL def-supplied?)) "Return a property value associated with the symbol or `def` if missing. If the default value is not supplied and the property is missing, an exception will be thrown." :doc-group prop :doc-see putprop (let ((kt (get *properties* key NIL))) (if def-supplied? (or (and kt (get kt symbol def)) def) (if kt (get kt symbol) (raise (list 'key-error key)))))) (def (remprop symbol key) "Remove a property value associated with the symbol." :doc-group prop (void (let ((kt (get *properties* key NIL))) (and kt (has? kt symbol) (del! kt symbol))))) ;;; documentation (def (separate-doc-from-body body (doc NIL)) "Take a list of terms and return a pair `(doc . body)`, where the first element contains a list of documentation-related terms, and the second contains the rest of the terms." :doc-group doc (def (doc? kw) (<= :doc-a kw :doc-z)) (let {[hd (car body)] [tl (cdr body)]} (cond [(and (str? hd) (not doc) tl) (separate-doc-from-body tl (cons hd doc))] [(and doc (doc? hd)) (separate-doc-from-body (cdr tl) (cons (cons hd (car tl)) doc))] [else (cons (reverse doc) body)]))) (def (sym-set-doc symbol doc-seq . formals-list) "Set the documentation for the symbol." :doc-group doc (def (formals-clean fs) (when (atom? fs) (return fs)) (let ((f (car fs))) (cons (if (and (cons? f) (length> f 2)) (subseq f 0 2) f) (formals-clean (cdr fs))))) (let* {[doc-only (str? doc-seq)] [doc (if doc-only doc-seq (car doc-seq))] [extra (if doc-only NIL (cdr doc-seq))] [formals-list (map formals-clean formals-list)]} (when (and (bound? 'str-join) doc) (let* {[lines (str-split doc "\n")] [hd (car lines)] [tl (cdr lines)] [snd (any (λ (s) (and (> (length s) 0) (rune-whitespace? (str-rune s 0)) s)) tl)] [indent (and snd (- (length snd) (length (str-trim snd))))] [trimmed (and snd (map (λ (s) (if (<= indent (length s)) (str-sub s indent) s)) tl))] [final (str-join (cons hd trimmed) "\n")]} (putprop symbol '*doc* final) (when extra (putprop symbol '*doc-extra* extra)))) (when (cons? formals-list) (putprop symbol '*formals-list* (delete-duplicates [append (getprop symbol '*formals-list* NIL) formals-list]))) #.(void))) (def (help-print-header term sigs (:kind NIL) (:lpad "")) "Format and print signature(s) of the term for `(help term)` output." :doc-group doc (def (print-type e) (set! print-type void) (princ " ;; [" [cond ((not (sym? e)) (type-of e)) ((and (sym? e) (bound? e)) (type-of (top-level-value term))) ((get-syntax e) "macro") (else "any")] "]")) (if sigs (for-each (λ (sig) (princ lpad) (print (cons term sig)) (print-type term) (newline)) sigs) (princ lpad) (if kind (begin (princ (caddr term)) (print-type "doc group")) (print term) (print-type term)) (newline)) (newline)) (defmacro (help topic (:print-header help-print-header) . rest) "Display documentation for a specific term or group of terms, if available. An optional symbol `group` is used to query for documentation on a group instead of a single term. All available documentation groups can be displayed with `(help groups)`. Asterisk can be added to the beginning and/or end of the term in order to list the matching terms defined in the current environment. This can be useful to recall a function's name. Examples: (help str?) ; show documentation for str? (help groups) ; show documentation groups (help type group) ; list items for dealing with types (help group type) ; same as ^ (help str->*) ; find functions converting from strings (help *->str) ; find functions converting to strings (help *num*) ; find anything related to numbers" :doc-group doc (let* {[term (if (eq? topic 'group) (car rest) topic)] [kind (if (eq? topic term) (car rest) topic)] [doc-extra-term (and kind (cons (sym ":doc-" kind) term))] [docterm (if kind (list 'doc kind term) term)] [doc (getprop docterm '*doc* NIL)] [formals-list (getprop docterm '*formals-list* NIL)] [term-bound (and (sym? term) (bound? term))]} (def (environment-find-matching) (let* {[s (str term)] [ts (eq? 0 (str-find s "*"))] ; starts with [s (or (and ts (str-sub s 1)) s)] [ei (1- (length s))] [te (eq? (str-find s "*") ei)] [s (or (and te (str-sub s 0 ei)) s)] [slen (length s)] [matches? (λ (term) (let* {[name (str term)] [i (str-find name s)] [nlen (and i (length name))]} (and i (or ts (= 0 i)) (or te (= nlen (+ i slen))))))] [matching (nconc (filter matches? (environment)) (filter matches? (table-keys *syntax-environment*)))]} (when matching (for-each (λ (term) (princ term) (newline)) (sort matching <))))) (def (print-sig term sigs lpad) (if sigs (for-each (λ (sig) (newline) (princ lpad) (princ (cons term sig))) sigs) (newline) (princ lpad) (princ term))) (def (first-line s) (str-sub s 0 (str-find s "\n"))) (def (doc-group? k) (and (cons? k) (eq? (car k) 'doc) (eq? (cadr k) 'group))) (def (doc-extra-term? k) (and (atom? k) (member doc-extra-term (getprop k '*doc-extra* NIL)))) (def (table-keys-filter-sort tbl pred) (sort (table-fold (λ (k _ z) (if (pred k) (cons k z) z)) NIL tbl) <)) (if (eq? term 'groups) (for-each (λ (k) (princ (str-rpad (str (caddr k)) 10) (first-line (getprop k '*doc* NIL))) (newline)) (table-keys-filter-sort (get *properties* '*doc*) doc-group?)) (if (or doc formals-list) (begin (print-header docterm formals-list :kind kind) (let* {[extra (getprop docterm '*doc-extra* NIL)] [fmt (filter (λ (v) (eq? (car v) :doc-fmt)) extra)] [see (filter (λ (v) (eq? (car v) :doc-see)) extra)]} (when doc (princ (foldl (λ (fmt doc) ((cdr fmt) doc)) doc fmt)) (newline)) (when see (newline) (princ "See also:") (newline) (for-each (λ (v) (print-sig (cdr v) (getprop (cdr v) '*formals-list* NIL) " ")) see) (newline))) (when kind (newline) (princ "Members:") (newline) (for-each (λ (k) (print-sig k (getprop k '*formals-list* NIL) " ")) (table-keys-filter-sort (get *properties* '*doc*) doc-extra-term?)) (newline)) #.(void)) (unless (and (not term-bound) (environment-find-matching)) (princ "no help for " (if kind (str kind " ") "") term) (when (and (not kind) (sym? term) (not term-bound)) (princ " (undefined)")) (newline)))) (void))) ;;; standard procedures (def (member item lst) "Return the tail of a list beginning with the item, or `NIL` otherwise. List elements are compared to the `item` using `equal?`. Examples: (member 1 '(3 2 1 0)) ; ↳ (1 0) (member 1 '(2 3)) ; ↳ NIL" :doc-group list :doc-see memq :doc-see memv (cond ((equal? (car lst) item) lst) (lst (member item (cdr lst))))) (def (memv item lst) "Return the tail of a list beginning with the item, or `NIL` otherwise. List elements are compared to the `item` using `eqv?`." :doc-group list :doc-see member :doc-see memq (cond ((eqv? (car lst) item) lst) (lst (memv item (cdr lst))))) (def (assoc-list . kvs) "Construct an association list from the arguments. Every two arguments are expected to be a key and a value associated with that key. Examples: (assoc-list 'a 0 'b 1) ; ↳ ((a . 0) (b . 1))" :doc-group list :doc-see assoc (let ((s (cdr kvs))) (when (cons? s) (cons (cons (car kvs) (car s)) (apply assoc-list (cdr s)))))) (def (assoc key lst) "Return a pair of a matching key and the associated value, or `NIL` if none matched. Keys are compared using `equal?`. Examples: (def L (assoc-list 'a 0 'b 1)) (assoc 'b L) ; ↳ (b . 1) (assoc 'c L) ; ↳ NIL" :doc-group list :doc-see assoc-list :doc-see assq :doc-see assv (cond ((equal? (caar lst) key) (car lst)) (lst (assoc key (cdr lst))))) (def (assv key lst) "Return a pair of a matching key and the associated value, or `NIL` if none matched. Keys are compared using `eqv?`." :doc-group list :doc-see assoc :doc-see assq (cond ((eqv? (caar lst) key) (car lst)) (lst (assv key (cdr lst))))) (doc-group compare "Comparison operators.") (def (> v . rest) "Return `T` if the arguments are in strictly decreasing order (previous one is greater than the next one)." :doc-group compare (let loop ((v v) (rest rest)) (or (not rest) (and (< (car rest) v) (loop (car rest) (cdr rest)))))) (defmacro (> v . rest) `(< ,.(reverse rest) ,v)) (def (<= v . rest) "Return `T` if the arguments are in non-decreasing order (previous one is less than or equal to the next one)." :doc-group compare (let loop ((v v) (rest rest)) (or (not rest) (unless (or (< (car rest) v) (nan? v)) (loop (car rest) (cdr rest)))))) (def (>= v . rest) "Return `T` if the arguments are in non-increasing order (previous one is greater than or equal to the next one)." :doc-group compare (let loop ((v v) (rest rest)) (or (not rest) (unless (or (< v (car rest)) (nan? v)) (loop (car rest) (cdr rest)))))) (doc-group number "Operations on numbers, mathematical constants.") (def (negative? n) "Return `T` if `n` is a negative number. Shorthand for `(< n 0)`." :doc-group number :doc-group compare (< n 0)) (def (zero? n) "Return `T` if `n` is zero. Shorthand for `(= n 0)`." :doc-group number :doc-group compare (= n 0)) (def (positive? n) "Return `T` if `n` is greater than zero. Shorthand for `(> n 0)`." :doc-group number :doc-group compare (< 0 n)) (def (even? n) "Return `T` if `n` is an even integer, `NIL` otherwise." :doc-group number :doc-see odd? (= (logand n 1) 0)) (def (odd? n) "Return `T` if `n` is an odd integer, `NIL` otherwise." :doc-group number :doc-see even? (not (even? n))) (def (1+ n) "Equivalent to `(+ n 1)` - increment by one." :doc-group number :doc-see 1- (+ n 1)) (def (1- n) "Equivalent to `(- n 1)` - decrement by one." :doc-group number :doc-see 1+ (- n 1)) (def (div a n) "Return the quotient of the Euclidean division `a/n`. Examples: (div 10 3) ; ↳ 3 (div -10 3) ; ↳ -4 (div -10 -3) ; ↳ 4 (div 10 -3) ; ↳ -3" :doc-group number :doc-see mod :doc-see div0 (+ (div0 a n) (or (and (< a 0) (or (and (< n 0) 1) -1)) 0))) (def (mod a n) "Return the remainder of the Euclidean division `a/n`. Examples: (mod 10 3) ; ↳ 1 (mod -10 3) ; ↳ 2 (mod -10 -3) ; ↳ 2 (mod 10 -3) ; ↳ 1" :doc-group number :doc-see div :doc-see mod0 (- a (* (div a n) n))) (def (mod0 a n) "Return the remainder of the truncated division `a/n`. Examples: (mod0 10 3) ; ↳ 1 (mod0 -10 3) ; ↳ -1