将lisp函数转换为使用映射
您好,我期待转换我现有的功能:将lisp函数转换为使用映射,lisp,common-lisp,Lisp,Common Lisp,您好,我期待转换我现有的功能: (defun checkMember (L A) (cond ((NULL L) nil) ( (and (atom (car L)) (equal (car L) A)) T ) (T (checkMember (cdr L) A)))) 使用映射函数,但我真的不能确切地理解映射函数是如何工作的,你能告诉我这个函数是如何工作的吗 这是我的演讲: (defun checkMem (L A) (cond ((NULL L
(defun checkMember (L A)
(cond
((NULL L) nil)
( (and (atom (car L)) (equal (car L) A)) T )
(T (checkMember (cdr L) A))))
使用映射函数,但我真的不能确切地理解映射函数是如何工作的,你能告诉我这个函数是如何工作的吗
这是我的演讲:
(defun checkMem (L A)
(cond
((NULL L) nil)
( (and (atom (car L)) (equal (car L) (car A))) T )
(T (mapcar #'checkMem (cdr L) A))))
试试这个
递归版本:
(defun checkmember (l a)
(let ((temp nil))
(cond ((null l) nil) ((find a l) (setf temp (or temp t)))
(t
(mapcar #'(lambda (x) (cond ((listp x)(setf temp (or temp (checkmember x a))))))
l)))
temp))
用法:(checkmember'(1(25)3)20)
=>无
(checkmember'(1(25)3)2)
=>T
(checkmember'(1 2 3)2)
=>T
(checkmember'(((((((((((((((((((1)))))))1)
=T这个呢:
(defun checkMember (L a)
(car (mapcan #'(lambda (e)
(and (equal a e) (list T)))
L)))
注意:它不会递归到列表元素中,但原始函数也没有递归到列表元素中。映射函数在这里不合适,因为任务涉及搜索列表以确定它是否包含匹配项。这不是映射 映射意味着通过某个函数传递每个元素(通常以某种方式收集返回值)。当然,我们可以滥用映射来解决问题 但是我可以建议这是一个reduce问题而不是映射问题吗?缩减意味着处理列表中的所有元素,以便生成一个汇总该列表的值 预热:使用
reduce
将元素添加到一起:
(reduce #'+ '(1 2 3)) -> 6
在我们的例子中,我们希望以不同的方式减少列表:根据列表是否包含某些项,将列表缩减为单个值,即T
或NIL
解决方案:
(defun is-member (list item)
(reduce (lambda (found next-one) (or found (eql next-one item)))
list :initial-value nil))
;; tests:
(is-member nil nil) -> NIL
(is-member nil 42) -> NIL
(is-member '(1) 1) -> T
(is-member '(1) 2) -> NIL
(is-member '(t t) 1) -> NIL ;; check for accumulator/item mixup
(is-member '(1 2) 2) -> T
(is-member '(1 2) 3) -> NIL
...
使用(左关联)reduce函数的一种常见模式是将每个reduce中的左参数视为累加值,该累加值通过reduce“线程化”。当我们使用+
进行简单的reduce以添加数字时,我们不会考虑这一点,但是用于reduce的函数的左参数始终是部分和。部分和初始化为零,因为reduce
首先调用+
函数时没有参数,这是可能的:(+)
在Lisp中为零
具体地说,在(reduce#'+'(1 2 3))
中发生的是:
- 首先,
调用reduce
,返回(+)
0
- 然后,减少调用
,这将产生部分和(+01)
1
- 接下来,减少调用
,使用前面的部分和作为左参数,使用下一个元素作为右参数。当然,这会返回(+12)
3
- 最后,减少调用
,结果是(+3)
6
found
。我们使用:initial value nil
显式指定初始值,因为我们的lambda函数不支持无参数调用。在每次调用lambda时,我们都会短路:如果found
为true,这意味着前面的缩减已经决定列表包含该项,我们只返回true。否则,我们将检查正确的参数:列表中的下一项。如果它等于item
,则返回T
,否则返回NIL
。然后,这个T
或NIL
在下一次调用中成为found
值。一旦我们返回T
,该值将通过剩余的缩减过程“多米诺骨牌”,从而导致T
从reduce
返回
如果坚持使用映射,您可以这样做:将每个元素映射到一个列表,如果元素与项不匹配,则该列表为空,否则为非空。以列表链接在一起的方式进行映射。如果结果列表为非空,则原始列表必须包含该项的一个或多个匹配项:
(defun is-member (list item)
(if (mapcan (lambda (elem)
(if (eq elem item) (list elem))) list)
t))
如果列表中包含许多项目,这种方法会执行大量浪费的分配
(
reduce
方法也是浪费,因为它在返回值明显为T
之后继续处理列表)它不起作用checkmember
是一个接受两个参数的函数,但mapcar
需要一个接受一个参数的函数。另外,(checkMember'(1 2 3)2)
不会返回T
。由于[31]>(memberLambda'(1 2 3)3)(NIL NIL T)
而无法正常工作,但我仍会努力找到一个way@Fr里德·里杜蒙特希望它现在对所有情况都有效。不,它不是。尝试(isthere'((1)))1
@FrédéricDumont Fixed,感谢您提醒我注意,我认为简单的列表检查是理所当然的。因此使用lambdas的映射函数将是一种处理问题的方式吗?:DNo,一点也不。使用map
或relative进行这种搜索是很奇怪的。但这是可能的。还有一个问题,是否有可能扩展同一个lambda,以一种新的方式进行工作?(能够识别任何级别的元素)?是的。实施只是一个练习。您认为如何D(defun checkMemberL(la)(car(mapcan#’)(lambda(e)(cond((atom e)(and(equal a e))))((listpe)checkMemberL(e,a)))L))
,在“查找某物”的特定情况下,理论上,这可以使用特例减缩器ANY
。优秀的Answare,如果我的马铃薯老师能够这样解释的话…(很遗憾,考试已经结束,现在正在等待结果)非常感谢您提供的所有质量信息。我们已经很好地解释了这一点,但它并不完全准确,因为在本例中,函数不是用零参数调用的。如果子序列为空且未给出初始值,则调用该函数时使用零参数,并且reduce返回函数所做的任何操作。这是调用该函数的唯一情况
(defun memb (item list)
(map nil
(lambda (element)
(when (eql item element)
(return-from memb t)))
list))