Remove car and cdr in favor of first and rest (#1241)

* Remove uses of `car` and `cdr` in /hy

* Remove uses of `car` and `cdr` in quote tests

* Remove `car` and `cdr` in favor of `first` and `rest`

I beefed up the documentation and tests for `first` and `rest` while I was at it.

I defined `car` and `cdr` in native_tests.cons so the tests read a bit more naturally.
This commit is contained in:
Kodi Arfer 2017-03-06 08:34:40 -08:00 committed by Ryan Gonzalez
parent 8ecb17d1fd
commit 8b6a45e43a
8 changed files with 53 additions and 40 deletions

View File

@ -850,16 +850,26 @@ eval-when-compile
----------------- -----------------
first / car first
----------- -----
``first`` and ``car`` are macros for accessing the first element of a collection: ``first`` is a function for accessing the first element of a collection.
.. code-block:: clj .. code-block:: clj
=> (first (range 10)) => (first (range 10))
0 0
It is implemented as ``(next (iter coll) None)``, so it works with any
iterable, and if given an empty iterable, it will return ``None`` instead of
raising an exception.
.. code-block:: clj
=> (first (repeat 10))
10
=> (first [])
None
for for
--- ---
@ -1402,17 +1412,23 @@ periods in them. In fact, ``mymodule`` and ``M`` aren't defined by these
to do introspection of the current module's set of defined macros, which isn't to do introspection of the current module's set of defined macros, which isn't
really supported anyway. really supported anyway.
rest / cdr rest
---------- ----
``rest`` and ``cdr`` return the collection passed as an argument without the ``rest`` takes the given collection and returns an iterable of all but the
first element: first element.
.. code-block:: clj .. code-block:: clj
=> (rest (range 10)) => (list (rest (range 10)))
[1, 2, 3, 4, 5, 6, 7, 8, 9] [1, 2, 3, 4, 5, 6, 7, 8, 9]
Given an empty collection, it returns an empty iterable.
.. code-block:: clj
=> (list (rest []))
[]
set-comp set-comp
-------- --------

View File

@ -111,10 +111,10 @@ Returns a fresh :ref:`cons cell <hycons>` with car *a* and cdr *b*.
=> (setv a (cons 'hd 'tl)) => (setv a (cons 'hd 'tl))
=> (= 'hd (car a)) => (= 'hd (get a 0))
True True
=> (= 'tl (cdr a)) => (= 'tl (cut a 1))
True True

View File

@ -87,6 +87,9 @@
(with-decorator (method-decorator ~name) (with-decorator (method-decorator ~name)
(defn ~name ~params ~@body)))) (defn ~name ~params ~@body))))
(defn head-tail [l]
(, (get l 0) (cut l 1)))
(defmacro defn [name &rest bodies] (defmacro defn [name &rest bodies]
(def arity-overloaded? (fn [bodies] (def arity-overloaded? (fn [bodies]
(if (isinstance (first bodies) HyString) (if (isinstance (first bodies) HyString)
@ -97,17 +100,14 @@
(do (do
(def comment (HyString)) (def comment (HyString))
(if (= (type (first bodies)) HyString) (if (= (type (first bodies)) HyString)
(do (def comment (car bodies)) (def [comment bodies] (head-tail bodies)))
(def bodies (cdr bodies))))
(def ret `(do)) (def ret `(do))
(.append ret '(import [hy.contrib.multi [MultiDispatch]])) (.append ret '(import [hy.contrib.multi [MultiDispatch]]))
(for [body bodies] (for [body bodies]
(def let-binds (car body)) (def [let-binds body] (head-tail body))
(def body (cdr body))
(.append ret (.append ret
`(with-decorator MultiDispatch (defn ~name ~let-binds ~comment ~@body)))) `(with-decorator MultiDispatch (defn ~name ~let-binds ~comment ~@body))))
ret) ret)
(do (do
(setv lambda-list (first bodies)) (setv [lambda-list body] (head-tail bodies))
(setv body (rest bodies))
`(setv ~name (fn ~lambda-list ~@body))))) `(setv ~name (fn ~lambda-list ~@body)))))

View File

@ -59,16 +59,6 @@
`(do ~@body))) `(do ~@body)))
(defmacro car [thing]
"Get the first element of a list/cons"
`(get ~thing 0))
(defmacro cdr [thing]
"Get all the elements of a thing, except the first"
`(cut ~thing 1))
(defmacro cond [&rest branches] (defmacro cond [&rest branches]
"shorthand for nested ifs: "shorthand for nested ifs:
(cond [foo bar] [baz quux]) -> (cond [foo bar] [baz quux]) ->
@ -87,8 +77,8 @@
(macro-error branch "cond branches need to be a list")) (macro-error branch "cond branches need to be a list"))
(if (< (len branch) 2) (if (< (len branch) 2)
(macro-error branch "cond branches need at least two items: a test and one or more code branches")) (macro-error branch "cond branches need at least two items: a test and one or more code branches"))
(setv test (car branch)) (setv test (first branch))
(setv thebranch (cdr branch)) (setv thebranch (cut branch 1))
`(if ~test (do ~@thebranch))) `(if ~test (do ~@thebranch)))
(setv root (check-branch branch)) (setv root (check-branch branch))

View File

@ -114,8 +114,8 @@
(defmacro ap-reduce [form lst &optional [initial-value None]] (defmacro ap-reduce [form lst &optional [initial-value None]]
"Anaphoric form of reduce, `acc' and `it' can be used for a form" "Anaphoric form of reduce, `acc' and `it' can be used for a form"
`(do `(do
(setv acc ~(if (none? initial-value) `(car ~lst) initial-value)) (setv acc ~(if (none? initial-value) `(get ~lst 0) initial-value))
(ap-each ~(if (none? initial-value) `(cdr ~lst) lst) (ap-each ~(if (none? initial-value) `(cut ~lst 1) lst)
(setv acc ~form)) (setv acc ~form))
acc)) acc))
@ -142,11 +142,11 @@
(str i))) (str i)))
[i (range 1 [i (range 1
;; find the maximum xi ;; find the maximum xi
(inc (max (+ (list-comp (int (cdr a)) (inc (max (+ (list-comp (int (cut a 1))
[a flatbody] [a flatbody]
(and (symbol? a) (and (symbol? a)
(.startswith a 'x) (.startswith a 'x)
(.isdigit (cdr a)))) (.isdigit (cut a 1))))
[0]))))]) [0]))))])
;; generate the &rest parameter only if 'xi is present in body ;; generate the &rest parameter only if 'xi is present in body
~@(if (in 'xi flatbody) ~@(if (in 'xi flatbody)

View File

@ -1,3 +1,7 @@
(defmacro car [x] `(get ~x 0))
(defmacro cdr [x] `(cut ~x 1))
(defn test-cons-mutability [] (defn test-cons-mutability []
"Test the mutability of conses" "Test the mutability of conses"
(setv tree (cons (cons 1 2) (cons 2 3))) (setv tree (cons (cons 1 2) (cons 2 3)))

View File

@ -681,10 +681,11 @@
(defn test-first [] (defn test-first []
"NATIVE: test firsty things" "NATIVE: test first"
(assert (= (first [1 2 3 4 5]) 1)) (assert (= (first [1 2 3 4 5]) 1))
(assert (is (first []) None)) (assert (= (first (range 10)) 0))
(assert (= (car [1 2 3 4 5]) 1))) (assert (= (first (repeat 10)) 10))
(assert (is (first []) None)))
(defn test-cut [] (defn test-cut []
@ -710,7 +711,9 @@
(defn test-rest [] (defn test-rest []
"NATIVE: test rest" "NATIVE: test rest"
(assert (= (list (rest [1 2 3 4 5])) [2 3 4 5]))) (assert (= (list (rest [1 2 3 4 5])) [2 3 4 5]))
(assert (= (list (take 3 (rest (iterate inc 8)))) [9 10 11]))
(assert (= (list (rest [])) [])))
(defn test-importas [] (defn test-importas []

View File

@ -11,8 +11,8 @@
(defn test-quoted-hoistable [] (defn test-quoted-hoistable []
"NATIVE: check whether quote works on hoisted things" "NATIVE: check whether quote works on hoisted things"
(setv f (quote (if True True True))) (setv f (quote (if True True True)))
(assert (= (car f) (quote if))) (assert (= (get f 0) (quote if)))
(assert (= (cdr f) (quote (True True True))))) (assert (= (cut f 1) (quote (True True True)))))
(defn test-quoted-macroexpand [] (defn test-quoted-macroexpand []
@ -20,8 +20,8 @@
(setv q1 (quote (-> a b c))) (setv q1 (quote (-> a b c)))
(setv q2 (quasiquote (-> a b c))) (setv q2 (quasiquote (-> a b c)))
(assert (= q1 q2)) (assert (= q1 q2))
(assert (= (car q1) (quote ->))) (assert (= (get q1 0) (quote ->)))
(assert (= (cdr q1) (quote (a b c))))) (assert (= (cut q1 1) (quote (a b c)))))
(defn test-quote-dicts [] (defn test-quote-dicts []