diff --git a/AUTHORS b/AUTHORS index ae6d9e3..926eaf5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -84,3 +84,4 @@ * Andrew Silva * Zaheer Soebhan * Rob Day +* Eric Kaschalk diff --git a/hy/core/bootstrap.hy b/hy/core/bootstrap.hy index 4ecb243..7e6b4f3 100644 --- a/hy/core/bootstrap.hy +++ b/hy/core/bootstrap.hy @@ -7,7 +7,7 @@ ;;; They are automatically required everywhere, even inside hy.core modules. (defmacro if [&rest args] - "if with elif" + "Conditionally evaluate alternating test and then expressions." (setv n (len args)) (if* n (if* (= n 1) @@ -17,11 +17,11 @@ (if ~@(cut args 2)))))) (defmacro macro-error [location reason] - "error out properly within a macro" + "Error out properly within a macro at `location` giving `reason`." `(raise (hy.errors.HyMacroExpansionError ~location ~reason))) (defmacro defn [name lambda-list &rest body] - "define a function `name` with signature `lambda-list` and body `body`" + "Define `name` as a function with `lambda-list` signature and body `body`." (import hy) (if (not (= (type name) hy.HySymbol)) (macro-error name "defn takes a name as first argument")) diff --git a/hy/core/language.hy b/hy/core/language.hy index e4aa531..a939edc 100644 --- a/hy/core/language.hy +++ b/hy/core/language.hy @@ -22,15 +22,15 @@ (import [hy.importer [hy-eval :as eval]]) (defn butlast [coll] - "Returns coll except of last element." + "Return an iterator of all but the last item in `coll`." (drop-last 1 coll)) (defn coll? [coll] - "Checks whether item is a collection" + "Check if `coll` is iterable and not a string." (and (iterable? coll) (not (string? coll)))) (defn comp [&rest fs] - "Function composition" + "Return the function from composing the given functions `fs`." (if (not fs) identity (= 1 (len fs)) (first fs) (do (setv rfs (reversed fs) @@ -43,35 +43,36 @@ res)))) (defn complement [f] - "Create a function that reverses truth value of another function" + "Returns a new function that returns the logically inverted result of `f`." (fn [&rest args &kwargs kwargs] (not (f #* args #** kwargs)))) (defn cons [a b] - "Return a fresh cons cell with car = a and cdr = b" + "Return a fresh cons cell with car = `a` and cdr = `b`." (HyCons a b)) (defn cons? [c] - "Check whether c can be used as a cons object" + "Check whether `c` is a cons cell." (instance? HyCons c)) (defn constantly [value] - "Create a function that always returns the same value" + "Create a new function that always returns `value` regardless of its input." (fn [&rest args &kwargs kwargs] value)) (defn keyword? [k] - "Check whether k is a keyword" + "Check whether `k` is a keyword." (and (instance? (type :foo) k) (.startswith k (get :foo 0)))) (defn dec [n] - "Decrement n by 1" + "Decrement `n` by 1." (- n 1)) (defn disassemble [tree &optional [codegen False]] - "Return the python AST for a quoted Hy tree as a string. - If the second argument is true, generate python code instead." + "Return the python AST for a quoted Hy `tree` as a string. + +If the second argument `codegen` is true, generate python code instead." (import astor) (import hy.compiler) @@ -83,8 +84,7 @@ compiled)) (defn distinct [coll] - "Return a generator from the original collection with duplicates - removed" + "Return a generator from the original collection `coll` with no duplicates." (setv seen (set) citer (iter coll)) (for* [val citer] (if (not_in val seen) @@ -121,9 +121,8 @@ (defn exec [$code &optional $globals $locals] "Execute Python code. - The parameter names contain weird characters to discourage calling this - function with keyword arguments, which isn't supported by Python 3's - `exec`." +The parameter names contain weird characters to discourage calling this +function with keyword arguments, which isn't supported by Python 3's `exec`." (if (none? $globals) (do (setv frame (._getframe sys (int 1))) @@ -161,9 +160,9 @@ ;; also from itertools, but not in Python2, and without func option until 3.3 (defn accumulate [iterable &optional [func operator.add]] - "accumulate(iterable[, func]) --> accumulate object + "Accumulate `func` on `iterable`. - Return series of accumulated sums (or other binary function results)." +Return series of accumulated sums (or other binary function results)." (setv it (iter iterable) total (next it)) (yield total) @@ -172,29 +171,29 @@ (yield total))) (defn drop [count coll] - "Drop `count` elements from `coll` and yield back the rest" + "Drop `count` elements from `coll` and yield back the rest." (islice coll count None)) (defn drop-last [n coll] - "Return a sequence of all but the last n elements in coll." + "Return a sequence of all but the last `n` elements in `coll`." (setv iters (tee coll)) (map first (zip #* [(get iters 0) (drop n (get iters 1))]))) (defn empty? [coll] - "Return True if `coll` is empty" + "Check if `coll` is empty." (= 0 (len coll))) (defn even? [n] - "Return true if n is an even number" + "Check if `n` is an even number." (= (% n 2) 0)) (defn every? [pred coll] - "Return true if (pred x) is logical true for every x in coll, else false" + "Check if `pred` is true applied to every x in `coll`." (all (map pred coll))) (defn flatten [coll] - "Return a single flat list expanding all members of coll" + "Return a single flat list expanding all members of `coll`." (if (coll? coll) (_flatten coll []) (raise (TypeError (.format "{0!r} is not a collection" coll))))) @@ -207,11 +206,11 @@ result) (defn float? [x] - "Return True if x is float" + "Check if x is float." (isinstance x float)) (defn symbol? [s] - "Check whether s is a symbol" + "Check if `s` is a symbol." (instance? HySymbol s)) (import [threading [Lock]]) @@ -219,6 +218,7 @@ (setv _gensym_lock (Lock)) (defn gensym [&optional [g "G"]] + "Generate a unique symbol for use in macros without accidental name clashes." (setv new_symbol None) (global _gensym_counter) (global _gensym_lock) @@ -237,93 +237,95 @@ (get f.f_globals "__name__")) (defn first [coll] - "Return first item from `coll`" + "Return first item from `coll`." (next (iter coll) None)) (defn identity [x] - "Returns the argument unchanged" + "Return `x`." x) (defn inc [n] - "Increment n by 1" + "Increment `n` by 1." (+ n 1)) (defn instance? [klass x] + "Perform `isinstance` with reversed arguments." (isinstance x klass)) (defn integer [x] - "Return Hy kind of integer" + "Return Hy kind of integer for `x`." (long-type x)) (defn integer? [x] - "Return True if x is an integer" + "Check if `x` is an integer." (isinstance x (, int long-type))) (defn integer-char? [x] - "Return True if char `x` parses as an integer" + "Check if char `x` parses as an integer." (try (integer? (int x)) (except [ValueError] False) (except [TypeError] False))) (defn interleave [&rest seqs] - "Return an iterable of the first item in each of seqs, then the second etc." + "Return an iterable of the first item in each of `seqs`, then the second etc." (chain.from-iterable (zip #* seqs))) (defn interpose [item seq] - "Return an iterable of the elements of seq separated by item" + "Return an iterable of the elements of `seq` separated by `item`." (drop 1 (interleave (repeat item) seq))) (defn iterable? [x] - "Return true if x is iterable" + "Check if `x` is an iterable." (isinstance x collections.Iterable)) (defn iterate [f x] + "Returns an iterator repeatedly applying `f` to seed `x`.. x, f(x), f(f(x))..." (setv val x) (while True (yield val) (setv val (f val)))) (defn iterator? [x] - "Return true if x is an iterator" + "Check if `x` is an iterator." (isinstance x collections.Iterator)) (defn juxt [f &rest fs] - "Return a function that applies each of the supplied functions to a single - set of arguments and collects the results into a list." + "Return a function applying each `fs` to args, collecting results in a list." (setv fs (cons f fs)) (fn [&rest args &kwargs kwargs] (list-comp (f #* args #** kwargs) [f fs]))) (defn last [coll] - "Return last item from `coll`" + "Return last item from `coll`." (get (tuple coll) -1)) (defn list* [hd &rest tl] - "Return a dotted list construed from the elements of the argument" + "Return a chain of nested cons cells (dotted list) containing `hd` and `tl`." (if (not tl) hd (cons hd (list* #* tl)))) (defn macroexpand [form] - "Return the full macro expansion of form" + "Return the full macro expansion of `form`." (import hy.macros) (setv name (calling-module-name)) (hy.macros.macroexpand form (HyASTCompiler name))) (defn macroexpand-1 [form] - "Return the single step macro expansion of form" + "Return the single step macro expansion of `form`." (import hy.macros) (setv name (calling-module-name)) (hy.macros.macroexpand-1 form (HyASTCompiler name))) (defn merge-with [f &rest maps] - "Returns a map that consists of the rest of the maps joined onto - the first. If a key occurs in more than one map, the mapping(s) - from the latter (left-to-right) will be combined with the mapping in - the result by calling (f val-in-result val-in-latter)." + "Return the map of `maps` joined onto the first via the function `f`. + +If a key occurs in more than one map, the mapping(s) from the latter +(left-to-right) will be combined with the mapping in the result by calling +(f val-in-result val-in-latter)." (if (any maps) (do (defn merge-entry [m e] @@ -337,31 +339,33 @@ (reduce merge2 maps)))) (defn neg? [n] - "Return true if n is < 0" + "Check if `n` is < 0." (< n 0)) (defn none? [x] - "Return true if x is None" + "Check if `x` is None" (is x None)) (defn numeric? [x] + "Check if `x` is an instance of numbers.Number." (import numbers) (instance? numbers.Number x)) (defn nth [coll n &optional [default None]] - "Return nth item in collection or sequence, counting from 0. - Return None if out of bounds unless specified otherwise." + "Return `n`th item in `coll` or None (specify `default`) if out of bounds." (next (drop n coll) default)) (defn odd? [n] - "Return true if n is an odd number" + "Check if `n` is an odd number." (= (% n 2) 1)) (def -sentinel (object)) (defn partition [coll &optional [n 2] step [fillvalue -sentinel]] - "Chunks coll into n-tuples (pairs by default). The remainder, if any, is not - included unless a fillvalue is specified. The step defaults to n, but can be - more to skip elements, or less for a sliding window with overlap." + "Chunk `coll` into `n`-tuples (pairs by default). + +The remainder, if any, is not included unless `fillvalue` is specified. The step +defaults to `n`, but can be more to skip elements, or less for a sliding window +with overlap." (setv step (or step n) coll-clones (tee coll n) @@ -372,46 +376,46 @@ (zip-longest #* slices :fillvalue fillvalue))) (defn pos? [n] - "Return true if n is > 0" + "Check if `n` is > 0." (> n 0)) (defn rest [coll] - "Get all the elements of a coll, except the first." + "Get all the elements of `coll`, except the first." (drop 1 coll)) (defn repeatedly [func] - "Yield result of running func repeatedly" + "Yield result of running `func` repeatedly." (while True (yield (func)))) (defn second [coll] - "Return second item from `coll`" + "Return second item from `coll`." (nth coll 1)) (defn some [pred coll] - "Return the first logical true value of (pred x) for any x in coll, else None" + "Return the first logical true value of applying `pred` in `coll`, else None." (first (filter None (map pred coll)))) (defn string [x] - "Cast x as current string implementation" + "Cast `x` as the current python verion's string implementation." (if-python2 (unicode x) (str x))) (defn string? [x] - "Return True if x is a string" + "Check if `x` is a string." (if-python2 (isinstance x (, str unicode)) (isinstance x str))) (defn take [count coll] - "Take `count` elements from `coll`, or the whole set if the total - number of entries in `coll` is less than `count`." + "Take `count` elements from `coll`." (islice coll None count)) (defn take-nth [n coll] - "Return every nth member of coll - raises ValueError for (not (pos? n))" + "Return every `n`th member of `coll`. + +Raises ValueError for (not (pos? n))." (if (not (pos? n)) (raise (ValueError "n must be positive"))) (setv citer (iter coll) skip (dec n)) @@ -421,13 +425,15 @@ (next citer)))) (defn zero? [n] - "Return true if n is 0" + "Check if `n` equals 0." (= n 0)) (defn read [&optional [from-file sys.stdin] [eof ""]] - "Read from input and returns a tokenized string. Can take a given input buffer - to read from, and a single byte as EOF (defaults to an empty string)" + "Read from input and returns a tokenized string. + +Can take a given input buffer to read from, and a single byte +as EOF (defaults to an empty string)." (setv buff "") (while True (setv inn (string (.readline from-file))) @@ -441,16 +447,17 @@ parsed) (defn read-str [input] - "Reads and tokenizes first line of input" + "Reads and tokenizes first line of `input`." (read :from-file (StringIO input))) (defn hyify [text] - "Convert text to match hy identifier" + "Convert `text` to match hy identifier." (.replace (string text) "_" "-")) (defn keyword [value] - "Create a keyword from the given value. Strings numbers and even objects - with the __name__ magic will work" + "Create a keyword from `value`. + +Strings numbers and even objects with the __name__ magic will work." (if (and (string? value) (value.startswith HyKeyword.PREFIX)) (hyify value) (if (string? value) @@ -460,8 +467,10 @@ (except [] (HyKeyword (+ ":" (string value)))))))) (defn name [value] - "Convert the given value to a string. Keyword special character will be stripped. - String will be used as is. Even objects with the __name__ magic will work" + "Convert `value` to a string. + +Keyword special character will be stripped. String will be used as is. +Even objects with the __name__ magic will work." (if (and (string? value) (value.startswith HyKeyword.PREFIX)) (hyify (cut value 2)) (if (string? value) @@ -471,7 +480,7 @@ (except [] (string value)))))) (defn xor [a b] - "Perform exclusive or between two parameters" + "Perform exclusive or between `a` and `b`." (if (and a b) False (or a b))) diff --git a/hy/core/macros.hy b/hy/core/macros.hy index e9f9f6f..d8ee145 100644 --- a/hy/core/macros.hy +++ b/hy/core/macros.hy @@ -10,11 +10,14 @@ (import [hy.models [HyList HySymbol]]) (defmacro as-> [head name &rest rest] - "Expands to sequence of assignments to the provided name, starting with head. - The previous result is thus available in the subsequent form. Returns the - final result, and leaves the name bound to it in the local scope. This behaves - much like the other threading macros, but requires you to specify the threading - point per form via the name instead of always the first or last argument." + "Beginning with `head`, expand a sequence of assignments `rest` to `name`. + +Each assignment is passed to the subsequent form. Returns the final assignment, +leaving the name bound to it in the local scope. + +This behaves similarly to other threading macros, but requires specifying +the threading point per-form via the name, rather than fixing to the first +or last argument." `(do (setv ~name ~head ~@(interleave (repeat name) rest)) @@ -22,6 +25,10 @@ (defmacro assoc [coll k1 v1 &rest other-kvs] + "Associate key/index value pair(s) to a collection `coll` like a dict or list. + +If more than three parameters are given, the remaining args are k/v pairs to +be associated in pairs." (if (odd? (len other-kvs)) (macro-error (last other-kvs) "`assoc` takes an odd number of arguments")) @@ -37,12 +44,13 @@ (defmacro with [args &rest body] - "shorthand for nested with* loops: + "Wrap execution of `body` within a context manager given as bracket `args`. + +Shorthand for nested with* loops: (with [x foo y bar] baz) -> (with* [x foo] (with* [y bar] - baz))" - + baz))." (if (not (empty? args)) (do (if (>= (len args) 2) @@ -56,12 +64,10 @@ (defmacro cond [&rest branches] - "shorthand for nested ifs: - (cond [foo bar] [baz quux]) -> - (if foo - bar - (if baz - quux))" + "Build a nested if clause with each `branch` a [cond result] bracket pair. + +The result in the bracket may be omitted, in which case the condition is also +used as the result." (if (empty? branches) None (do @@ -88,13 +94,10 @@ (defmacro for [args &rest body] - "shorthand for nested for loops: - (for [x foo - y bar] - baz) -> - (for* [x foo] - (for* [y bar] - baz))" + "Build a for-loop with `args` as a [element coll] bracket pair and run `body`. + +Args may contain multiple pairs, in which case it executes a nested for-loop +in order of the given pairs." (setv body (list body)) (if (empty? body) (macro-error None "`for' requires a body to evaluate")) @@ -113,10 +116,10 @@ (defmacro -> [head &rest rest] - "Threads the head through the rest of the forms. Inserts - head as the second item in the first form of rest. If - there are more forms, inserts the first form as the - second item in the second form of rest, etc." + "Thread `head` first through the `rest` of the forms. + +The result of the first threaded form is inserted into the first position of +the second form, the second result is inserted into the third form, and so on." (setv ret head) (for* [node rest] (if (not (isinstance node HyExpression)) @@ -127,8 +130,7 @@ (defmacro doto [form &rest expressions] - "Performs a sequence of potentially mutating actions - on an initial object, returning the resulting object" + "Perform possibly mutating `expressions` on `form`, returning resulting obj." (setv f (gensym)) (defn build-form [expression] (if (isinstance expression HyExpression) @@ -140,10 +142,10 @@ ~f)) (defmacro ->> [head &rest rest] - "Threads the head through the rest of the forms. Inserts - head as the last item in the first form of rest. If there - are more forms, inserts the first form as the last item - in the second form of rest, etc." + "Thread `head` last through the `rest` of the forms. + +The result of the first threaded form is inserted into the last position of +the second form, the second result is inserted into the third form, and so on." (setv ret head) (for* [node rest] (if (not (isinstance node HyExpression)) @@ -185,6 +187,7 @@ (defmacro with-gensyms [args &rest body] + "Execute `body` with `args` as bracket of names to gensym for use in macros." (setv syms []) (for* [arg args] (.extend syms [arg `(gensym '~arg)])) @@ -193,6 +196,7 @@ ~@body)) (defmacro defmacro/g! [name args &rest body] + "Like `defmacro`, but symbols prefixed with 'g!' are gensymed." (setv syms (list (distinct (filter (fn [x] @@ -207,8 +211,9 @@ ~@body)) (defmacro defmacro! [name args &rest body] - "Like defmacro/g! plus automatic once-only evaluation for o! - parameters, which are available as the equivalent g! symbol." + "Like `defmacro/g!`, with automatic once-only evaluation for 'o!' params. + +Such 'o!' params are availible within `body` as the equivalent 'g!' symbol." (setv os (list-comp s [s args] (.startswith s "o!")) gs (list-comp (HySymbol (+ "g!" (cut s 2))) [s os])) `(defmacro/g! ~name ~args @@ -217,7 +222,7 @@ (defmacro defmain [args &rest body] - "Write a function named \"main\" and do the if __main__ dance" + "Write a function named \"main\" and do the 'if __main__' dance" (setv retval (gensym)) `(when (= --name-- "__main__") (import sys) diff --git a/hy/core/shadow.hy b/hy/core/shadow.hy index ef63da6..bfb1e5f 100644 --- a/hy/core/shadow.hy +++ b/hy/core/shadow.hy @@ -9,7 +9,7 @@ (defn + [&rest args] - "Shadow + operator for when we need to import / map it against something" + "Shadowed `+` operator adds `args`." (if (= (len args) 0) 0 @@ -19,13 +19,13 @@ (reduce operator.add args))) (defn - [a1 &rest a-rest] - "Shadow - operator for when we need to import / map it against something" + "Shadowed `-` operator subtracts each `a-rest` from `a1`." (if a-rest (reduce operator.sub a-rest a1) (- a1))) (defn * [&rest args] - "Shadow * operator for when we need to import / map it against something" + "Shadowed `*` operator multiplies `args`." (if (= (len args) 0) 1 @@ -35,6 +35,7 @@ (reduce operator.mul args))) (defn ** [a1 a2 &rest a-rest] + "Shadowed `**` operator takes `a1` to the power of `a2`, ..., `a-rest`." ; We use `-foldr` instead of `reduce` because exponentiation ; is right-associative. (-foldr operator.pow (+ (, a1 a2) a-rest))) @@ -42,32 +43,40 @@ (reduce (fn [x y] (f y x)) (cut xs None None -1))) (defn / [a1 &rest a-rest] - "Shadow / operator for when we need to import / map it against something" + "Shadowed `/` operator divides `a1` by each `a-rest`." (if a-rest (reduce operator.truediv a-rest a1) (/ 1 a1))) (defn // [a1 a2 &rest a-rest] + "Shadowed `//` operator floor divides `a1` by `a2`, ..., `a-rest`." (reduce operator.floordiv (+ (, a2) a-rest) a1)) (defn % [x y] + "Shadowed `%` operator takes `x` modulo `y`." (% x y)) -(if PY35 (defn @ [a1 &rest a-rest] - (reduce operator.matmul a-rest a1))) +(if PY35 + (defn @ [a1 &rest a-rest] + "Shadowed `@` operator matrix multiples `a1` by each `a-rest`." + (reduce operator.matmul a-rest a1))) (defn << [a1 a2 &rest a-rest] + "Shadowed `<<` operator performs left-shift on `a1` by `a2`, ..., `a-rest`." (reduce operator.lshift (+ (, a2) a-rest) a1)) (defn >> [a1 a2 &rest a-rest] + "Shadowed `>>` operator performs right-shift on `a1` by `a2`, ..., `a-rest`." (reduce operator.rshift (+ (, a2) a-rest) a1)) (defn & [a1 &rest a-rest] + "Shadowed `&` operator performs bitwise-and on `a1` by each `a-rest`." (if a-rest (reduce operator.and_ a-rest a1) a1)) (defn | [&rest args] + "Shadowed `|` operator performs bitwise-or on `a1` by each `a-rest`." (if (= (len args) 0) 0 @@ -77,9 +86,11 @@ (reduce operator.or_ args))) (defn ^ [x y] + "Shadowed `^` operator performs bitwise-xor on `x` and `y`." (^ x y)) (defn ~ [x] + "Shadowed `~` operator performs bitwise-negation on `x`." (~ x)) (defn comp-op [op a1 a-rest] @@ -89,29 +100,32 @@ (list-comp (op x y) [(, x y) (zip (+ (, a1) a-rest) a-rest)])) True)) (defn < [a1 &rest a-rest] - "Shadow < operator for when we need to import / map it against something" + "Shadowed `<` operator perform lt comparison on `a1` by each `a-rest`." (comp-op operator.lt a1 a-rest)) (defn <= [a1 &rest a-rest] - "Shadow <= operator for when we need to import / map it against something" + "Shadowed `<=` operator perform le comparison on `a1` by each `a-rest`." (comp-op operator.le a1 a-rest)) (defn = [a1 &rest a-rest] - "Shadow = operator for when we need to import / map it against something" + "Shadowed `=` operator perform eq comparison on `a1` by each `a-rest`." (comp-op operator.eq a1 a-rest)) (defn is [a1 &rest a-rest] + "Shadowed `is` keyword perform is on `a1` by each `a-rest`." (comp-op operator.is_ a1 a-rest)) (defn != [a1 a2 &rest a-rest] - "Shadow != operator for when we need to import / map it against something" + "Shadowed `!=` operator perform neq comparison on `a1` by `a2`, ..., `a-rest`." (comp-op operator.ne a1 (+ (, a2) a-rest))) (defn is-not [a1 a2 &rest a-rest] + "Shadowed `is-not` keyword perform is-not on `a1` by `a2`, ..., `a-rest`." (comp-op operator.is-not a1 (+ (, a2) a-rest))) (defn >= [a1 &rest a-rest] - "Shadow >= operator for when we need to import / map it against something" + "Shadowed `>=` operator perform ge comparison on `a1` by each `a-rest`." (comp-op operator.ge a1 a-rest)) (defn > [a1 &rest a-rest] - "Shadow > operator for when we need to import / map it against something" + "Shadowed `>` operator perform gt comparison on `a1` by each `a-rest`." (comp-op operator.gt a1 a-rest)) (defn and [&rest args] + "Shadowed `and` keyword perform and on `args`." (if (= (len args) 0) True @@ -121,6 +135,7 @@ (reduce (fn [x y] (and x y)) args))) (defn or [&rest args] + "Shadowed `or` keyword perform or on `args`." (if (= (len args) 0) None @@ -130,15 +145,19 @@ (reduce (fn [x y] (or x y)) args))) (defn not [x] + "Shadowed `not` keyword perform not on `x`." (not x)) (defn in [x y] + "Shadowed `in` keyword perform `x` in `y`." (in x y)) (defn not-in [x y] + "Shadowed `not in` keyword perform `x` not in `y`." (not-in x y)) (defn get [coll key1 &rest keys] + "Access item in `coll` indexed by `key1`, with optional `keys` nested-access." (setv coll (get coll key1)) (for* [k keys] (setv coll (get coll k)))