[英]Does Lisp have something like Haskell's takeWhile function?
I'm new to Common Lisp.我是 Common Lisp 的新手。 In Haskell, you can do a little something like this:
在 Haskell 中,您可以执行以下操作:
Prelude> takeWhile (<= 10) [k | k <- [1..]]
[1,2,3,4,5,6,7,8,9,10]
Is this possible in Lisp?这在 Lisp 中可行吗? Not necessarily with an infinite list, but with any list.
不一定是无限列表,而是任何列表。
You could use LOOP :你可以使用LOOP :
(setq *l1* (loop for x from 1 to 100 collect x))
(loop for x in *l1* while (<= x 10) collect x)
If you really need it as a separate function:如果你真的需要它作为单独的 function:
(defun take-while (pred list)
(loop for x in list
while (funcall pred x)
collect x))
And here we are:我们在这里:
T1> (take-while (lambda (x) (<= x 10)) *l1*)
(1 2 3 4 5 6 7 8 9 10)
But if we compare:但是如果我们比较:
(loop for x in *l1* while (<= x 10) collect x)
(take-while (lambda (x) (<= x 10)) *l1*)
I think I would just stick with loop.我想我会坚持使用循环。
For infinite sequences, you could take a look at Series :对于无限序列,您可以查看Series :
T1> (setq *print-length* 20)
20
T1> (setq *l1* (scan-range :from 1))
#Z(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ...)
T1> (until-if (lambda (x) (> x 10)) *l1*)
#Z(1 2 3 4 5 6 7 8 9 10)
This should do...这应该做...
(defun take-while (list test)
(and list (funcall test (car list))
(cons (car list) (take-while (cdr list) test))))
(take-while '(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) (lambda (x) (< x 10)))
--> (1 2 3 4 5 6 7 8 9)
However this "natural" implementation is not tail-recursive and could crash for big lists.然而,这种“自然”实现不是尾递归的,并且可能会因大列表而崩溃。
An explicit push-nreverse approach (a common pattern) could be一个明确的 push-nreverse 方法(一种常见的模式)可以是
(defun take-while (list test)
(do ((res nil))
((or (null list) (not (funcall test (car list))))
(nreverse res))
(push (car list) res)
(setf list (cdr list))))
A recursive (but tail-recursive, therefore probably ok with most CL implementations) could IMO be the following:递归(但尾递归,因此可能适用于大多数 CL 实现)可以 IMO 如下:
(defun take-while (list test)
(labels ((rec (res x)
(if (and x (funcall test (car x)))
(rec (cons (car x) res) (cdr x))
(nreverse res))))
(rec nil list)))
Note that however it's not guaranteed that a common lisp implementation will handle tail-call optimizations.请注意,但不能保证通用 lisp 实现将处理尾调用优化。
The CL-LAZY library implements lazy calling for Common Lisp and provides a take-while function that is laziness aware. CL-LAZY 库实现了 Common Lisp 的延迟调用,并提供了一个可感知延迟的 function。 You can install it with Quicklisp and try it out.
您可以使用Quicklisp安装它并尝试一下。
Some languages provide a Haskell-style list API as 3rd party libraries, with or without support for infinite streams.某些语言提供 Haskell 样式列表 API 作为 3rd 方库,支持或不支持无限流。
Some examples:一些例子:
Remember that takeWhile
is relatively easy to implement over a sequence, and is given in Haskell as:请记住,在序列上实现
takeWhile
相对容易,在 Haskell 中给出如下:
takeWhile _ [] = []
takeWhile p (x:xs)
| p x = x : takeWhile p xs
| otherwise = []
You can have a lazy evaluation in common lisp using closures (from Paul Graham's On Lisp ):您可以使用闭包(来自Paul Graham 的 On Lisp )在 common lisp 中进行惰性评估:
(defun lazy-right-fold (comb &optional base)
"Lazy right fold on lists."
(labels ((rec (lst)
(if (null lst)
base
(funcall comb
(car lst)
#'(lambda () (rec (cdr lst)))))))
#'rec))
Then, take-while becomes:然后,take-while 变成:
(defun take-while (pred lst)
(lazy-right-fold #'(lambda (x f) (
(if (test x)
(cons x (funcall f))
(funcall f)))
nil))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.