列表函数
head
函数用于获取列表的第一个元素,但它返回的内容仍然包含在列表中。如果我们想要从这个列表中实际地获取元素,我们需要以某种方式提取它。
单个元素列表仅计算该元素,因此我们可以使用该eval
函数进行提取。我们还可以定义一些辅助函数来帮助提取列表的第一,第二和第三个元素。我们稍后会使用这些函数。
; First, Second, or Third Item in List
(fun {fst l} { eval (head l) })
(fun {snd l} { eval (head (tail l)) })
(fun {trd l} { eval (head (tail (tail l))) })
几章前我们简要介绍了一些递归列表函数。当然,我们可以使用这种技术来定义更多函数。
为了找到列表的长度,我们可以递归它,为尾部的长度增加1
。为了找到列表的nth
元素,我们可以执行tail
操作并进行倒计数直到我们到达0
。要获取列表的最后一个元素,我们只需访问总长度减去1的位置的元素即可。
; List Length
(fun {len l} {
if (== l nil)
{0}
{+ 1 (len (tail l))}
})
; Nth item in List
(fun {nth n l} {
if (== n 0)
{fst l}
{nth (- n 1) (tail l)}
})
; Last item in List
(fun {last l} {nth (- (len l) 1) l})
有许多其他有用的函数遵循相同的模式。我们可以定义用于获取和删除列表前多个元素的函数,或者用于检查值是否是列表元素的函数。
; Take N items
(fun {take n l} {
if (== n 0)
{nil}
{join (head l) (take (- n 1) (tail l))}
})
; Drop N items
(fun {drop n l} {
if (== n 0)
{l}
{drop (- n 1) (tail l)}
})
; Split at N
(fun {split n l} {list (take n l) (drop n l)})
; Element of List
(fun {elem x l} {
if (== l nil)
{false}
{if (== x (fst l)) {true} {elem x (tail l)}}
})
这些函数都遵循类似的模式。如果有某种方法来提取这种模式会很好,所以我们不必每次都需要写代码。例如,我们可能想要一种可以对列表的每个元素执行某些功能的方法。这是我们可以定义为map
的函数 。它需要输入一些功能和一些列表。对于列表中的每个变量,只要是使用f
的变量,都将其追加到列表的前面。然后它将被map
用于列表的尾部。
; Apply Function to List
(fun {map f l} {
if (== l nil)
{nil}
{join (list (f (fst l))) (map f (tail l))}
})
有了这个,我们可以做一些看起来有点像循环的整洁的东西。在某些方面,这个概念比循环更强大。我们可以考虑立即对所有元素进行操作,而不是考虑依次对列表的每个元素执行某些功能。我们映射列表而不是更改每个元素。
lispy> map - {5 6 7 8 2 22 44}
{-5 -6 -7 -8 -2 -22 -44}
lispy> map (\ {x} {+ x 10}) {5 2 11}
{15 12 21}
lispy> print {"hello" "world"}
{"hello" "world"}
()
lispy> map print {"hello" "world"}
"hello"
"world"
{() ()}
lispy>
我们可以改变一下这个想法,这是一种filter
功能,它接受一些功能条件,并且仅包括与该条件匹配的列表项。
; Apply Filter to List
(fun {filter f l} {
if (== l nil)
{nil}
{join (if (f (fst l)) {head l} {nil}) (filter f (tail l))}
})
这就是它在实践中的样子。
lispy> filter (\ {x} {> x 2}) {5 2 11 -7 8 1}
{5 11 8}
某些循环并不完全作用于列表,而是累积一些循环或将列表压缩为单个值。这些是诸如求和和阶乘之类的循环。这些可以与我们已经定义的len
函数的表达非常相似。
这些被称为折叠,它们的工作方式如下。提供了一个函数f
,一个基值z
和一个列表,它们将列表l
中的每个元素与总值合并,从基值开始。
; Fold Left
(fun {foldl f z l} {
if (== l nil)
{z}
{foldl f (f z (fst l)) (tail l)}
})
使用折叠,我们可以非常优雅的方式定义sum
和product
功能。
(fun {sum l} {foldl + 0 l})
(fun {product l} {foldl * 1 l})