将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
在我们的例子中,通过归约得到的累积值不是一个部分和,而是一个布尔值。此布尔值变为左参数,该参数在reduce函数中被称为
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))