列表中的成员-LISP

列表中的成员-LISP,lisp,Lisp,我需要用Lisp编写一个程序来查看列表中特定字符的出现次数。例如,下列列表中出现的1[1,2,3,1,1]Lisp中的列表是cons节点序列:成对的指针-第一个指向有效负载数据,第二个指向列表的其余部分。例如,对于[1,2,3,1,1] . / \ 1 . / \ 2 . / \ 3 ...... . / \ 1 NIL

我需要用Lisp编写一个程序来查看列表中特定字符的出现次数。例如,下列列表中出现的1[1,2,3,1,1]

Lisp中的列表是cons节点序列:成对的指针-第一个指向有效负载数据,第二个指向列表的其余部分。例如,对于
[1,2,3,1,1]

      .
     / \
    1   .
       / \
      2   .
         / \
        3   ...... .
                  / \
                 1   NIL
NIL
是一个表示空列表的特殊值,这样系统就知道不再尝试进一步研究它。在计划中

(define NIL '())
(define (myfold f z list)
  (cond
      ((null? list) z)                ; replace NIL with the initial ("zero") value
      (else 
        (f                            ; combine
           (car list)                 ; the payload datum, and the delayed,
           (lambda ()                 ;   by creating a function to calculate it,
             (myfold f z              ;     result of recursively folding 
                     (cdr list))))))) ;       the rest of list
递归列表处理范式由以下概念捕获:每个节点用二进制函数“替换”,特殊节点用一些特殊的“零”值替换(f1(f2(f 3(…(f 1 z)…)。在方案中

(define NIL '())
(define (myfold f z list)
  (cond
      ((null? list) z)                ; replace NIL with the initial ("zero") value
      (else 
        (f                            ; combine
           (car list)                 ; the payload datum, and the delayed,
           (lambda ()                 ;   by creating a function to calculate it,
             (myfold f z              ;     result of recursively folding 
                     (cdr list))))))) ;       the rest of list
这样,组合函数
f
必须处理两个值:一个是节点的有效负载数据,另一个是递归折叠的(延迟)结果,具有相同的
f
z
,该节点之后的列表的其余部分

(define (keep-equals v list)
  (myfold
         (lambda (a r)         ; combine ...
           (if (equal? v a) 
             (cons a ... )     ; the same thing goes over the dots, here
             ... ))            ;                                and here
         '()                   ; replace the NIL of the argument list with this
         list))
由于递归折叠结果的计算是通过创建一个函数来延迟的,在需要结果时调用该函数,因此我们需要在确实需要这些结果时通过调用该函数来“强制”执行该计算

如果你想计算出现的次数而不是在列表中收集它们,你只需要使用不同的组合函数和不同的初始(“零”)值

特别是,我们通过
cons
将一个值添加到列表的其余部分(以NIL作为初始值,空列表)来构建一个列表;而我们通过递增一个计数器(以0作为该计数器的初始值)来计数


例如,通过折叠计算一个列表的长度,我们基本上把它的每个元素都转换成1:
length[a,b,c,d,e]==1+(1+(1+(1+(1+0)))
。在这里,组合函数将需要有条件地增加计数器,仅当有效负载数据达到我们想要计数的程度时。

Lisp中的列表是一系列cons节点:成对的指针-第一个指向有效负载数据,第二个指向列表的其余部分。例如,对于
[1,2,3,1,1]

      .
     / \
    1   .
       / \
      2   .
         / \
        3   ...... .
                  / \
                 1   NIL
NIL
是一个表示空列表的特殊值,这样系统就知道不再尝试进一步探索它。在Scheme中

(define NIL '())
(define (myfold f z list)
  (cond
      ((null? list) z)                ; replace NIL with the initial ("zero") value
      (else 
        (f                            ; combine
           (car list)                 ; the payload datum, and the delayed,
           (lambda ()                 ;   by creating a function to calculate it,
             (myfold f z              ;     result of recursively folding 
                     (cdr list))))))) ;       the rest of list
递归列表处理范式由以下概念捕获:每个节点用二进制函数“替换”,特殊节点用一些特殊的“零”值替换(f1(f2(f 3(…(f 1 z)…)。在方案中

(define NIL '())
(define (myfold f z list)
  (cond
      ((null? list) z)                ; replace NIL with the initial ("zero") value
      (else 
        (f                            ; combine
           (car list)                 ; the payload datum, and the delayed,
           (lambda ()                 ;   by creating a function to calculate it,
             (myfold f z              ;     result of recursively folding 
                     (cdr list))))))) ;       the rest of list
这样,组合函数
f
必须处理两个值:一个是节点的有效负载数据,另一个是递归折叠的(延迟)结果,具有相同的
f
z
,该节点之后的列表的其余部分

(define (keep-equals v list)
  (myfold
         (lambda (a r)         ; combine ...
           (if (equal? v a) 
             (cons a ... )     ; the same thing goes over the dots, here
             ... ))            ;                                and here
         '()                   ; replace the NIL of the argument list with this
         list))
由于递归折叠结果的计算是通过创建一个函数来延迟的,在需要结果时调用该函数,因此我们需要在确实需要这些结果时通过调用该函数来“强制”执行该计算

如果你想计算出现的次数而不是在列表中收集它们,你只需要使用不同的组合函数和不同的初始(“零”)值

特别是,我们通过
cons
将一个值添加到列表的其余部分(以NIL作为初始值,空列表)来构建一个列表;而我们通过递增一个计数器(以0作为该计数器的初始值)来计数


例如,通过折叠计算一个列表的长度,我们基本上把它的每个元素都转换成1:
length[a,b,c,d,e]==1+(1+(1+(1+(1+0)))
。在这里,组合函数将需要有条件地增加计数器,仅当有效负载数据达到我们想要计算它们的程度时。

我自己是lisp新手,但我会这样做。我还没有看过will给出的其他答案,所以我会在发布后检查。
成员
函数具有uti告诉您它是否在列表中找到了某些内容,并从发现位置开始返回该列表的其余部分:

CL-USER> (member '1 '(0 1 2 3))
(1 2 3)
然后,您可以递归调用使用
成员的函数,并从
let
中的变量中的返回值递增计数器:

(defun find1 (alist)
  (let ((count 0))
    (labels ((findit (list)
              (let ((part (member '1 list)))
                (if part
                  (progn (incf count)
                         (findit (rest part)))
                   0))
             count))
      (findit alist))))
结果如下:

CL-USER> (find1 '(1 2 3 4 5))    
1
CL-USER> (find1 '(1 1 2 3 4 5))
2
CL-USER> (find1 '(1 1 1 2 3 1 4 5 1 1))
6
通过使用
cond
而不是
if

更新:根据评论,这里是上述内容的更新版和更优雅的版本,我认为也可以称之为尾部递归:

(defun find1 (alist &optional (accum 0))
  (let ((part (member '1 alist)))
    (if part
     (find1 (rest part) (+ accum 1))
     accum)))
这就是它的作用:

CL-USER> (find1 '(1 2 3 4))    
1
CL-USER> (find1 '(1 1 1 1))
4
CL-USER> (find1 '(1 1 0 1 1))
4
CL-USER> (find1 '(0 2 1 0 1 1 0 1 1))
5

我自己对lisp还不熟悉,但我会这样做。我还没有看过Will的其他答案,所以我会在发布后检查。
member
函数既可以告诉您它是否在列表中找到了某个内容,也可以从找到该内容的位置返回该列表的其余部分:

CL-USER> (member '1 '(0 1 2 3))
(1 2 3)
然后,您可以递归调用使用
成员的函数,并从
let
中的变量中的返回值递增计数器:

(defun find1 (alist)
  (let ((count 0))
    (labels ((findit (list)
              (let ((part (member '1 list)))
                (if part
                  (progn (incf count)
                         (findit (rest part)))
                   0))
             count))
      (findit alist))))
结果如下:

CL-USER> (find1 '(1 2 3 4 5))    
1
CL-USER> (find1 '(1 1 2 3 4 5))
2
CL-USER> (find1 '(1 1 1 2 3 1 4 5 1 1))
6
通过使用
cond
而不是
if

更新:根据评论,这里是上述内容的更新版和更优雅的版本,我认为也可以称之为尾部递归:

(defun find1 (alist &optional (accum 0))
  (let ((part (member '1 alist)))
    (if part
     (find1 (rest part) (+ accum 1))
     accum)))
这就是它的作用:

CL-USER> (find1 '(1 2 3 4))    
1
CL-USER> (find1 '(1 1 1 1))
4
CL-USER> (find1 '(1 1 0 1 1))
4
CL-USER> (find1 '(0 2 1 0 1 1 0 1 1))
5

我很喜欢这个问题的答案。但看起来它们都比必要的工作量要多。另一方面,考虑到每个人的想法,我很高兴