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
=> (first (range 10))
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
---
@ -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
really supported anyway.
rest / cdr
----------
rest
----
``rest`` and ``cdr`` return the collection passed as an argument without the
first element:
``rest`` takes the given collection and returns an iterable of all but the
first element.
.. code-block:: clj
=> (rest (range 10))
=> (list (rest (range 10)))
[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
--------

View File

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

View File

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

View File

@ -59,16 +59,6 @@
`(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]
"shorthand for nested ifs:
(cond [foo bar] [baz quux]) ->
@ -87,8 +77,8 @@
(macro-error branch "cond branches need to be a list"))
(if (< (len branch) 2)
(macro-error branch "cond branches need at least two items: a test and one or more code branches"))
(setv test (car branch))
(setv thebranch (cdr branch))
(setv test (first branch))
(setv thebranch (cut branch 1))
`(if ~test (do ~@thebranch)))
(setv root (check-branch branch))

View File

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

View File

@ -681,10 +681,11 @@
(defn test-first []
"NATIVE: test firsty things"
"NATIVE: test first"
(assert (= (first [1 2 3 4 5]) 1))
(assert (is (first []) None))
(assert (= (car [1 2 3 4 5]) 1)))
(assert (= (first (range 10)) 0))
(assert (= (first (repeat 10)) 10))
(assert (is (first []) None)))
(defn test-cut []
@ -710,7 +711,9 @@
(defn 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 []

View File

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