首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >不返回LISP/计划中的任何内容

不返回LISP/计划中的任何内容
EN

Stack Overflow用户
提问于 2013-07-16 15:29:00
回答 3查看 602关注 0票数 5

基本上,我想使用map在列表中进行选择,如

代码语言:javascript
运行
复制
(define tbl '(a b c d))
(map (lambda (item 'c) (if (eq? item 'c) item (...what in else?) )))

我想要的结果是

代码语言:javascript
运行
复制
'(c)

我试着把其他部分保持为空,它抱怨说其他部分是必需的。我试过了

代码语言:javascript
运行
复制
(display "foo") 

因为其他的部分

代码语言:javascript
运行
复制
(#<void> #<void> c #<void>)

差不多了。

我能用地图得到'(c)‘吗?我知道递归的方法,但我想知道map是否也能做到这一点。如果不是'(c),至少(# #c #),但不使用显示黑客来实现空类型返回值。

EN

回答 3

Stack Overflow用户

发布于 2013-07-16 15:31:13

您希望使用filter,而不是map,因为输出列表可能比输入列表有更少的元素。所有由#<void>返回的display值都存在,因为map总是在输出列表中包含一个结果,即使对于那些我们不感兴趣的元素也是如此。

代码语言:javascript
运行
复制
(define tbl '(a b c d))

(filter (lambda (item) (eq? item 'c)) tbl)
=> '(c)

相当于,而且更短一点:

代码语言:javascript
运行
复制
(filter (curry eq? 'c) tbl)
=> '(c)

当您想要对输入列表中的每个元素做一些事情时,使用map,而不丢弃元素。另一方面,filter用于选择输入列表中的一些元素,那些为给定谓词计算到#t的元素,而filter在大多数Scheme解释器中都是可用的,如果它不可用,则可以导入SRFI-1或使用参考实施

没有办法只使用'(c)来获得map (可以使用map + applyremove*等攻击它,但这不是这个想法吗?);如果出于某种原因,您必须只使用map,并且不介意返回带有占位符的列表,下面是几个替代方案:

代码语言:javascript
运行
复制
(map (lambda (item) (if (eq? item 'c) item '%)) tbl) ; placeholder in else part
=> '(% % c %)

(map (lambda (item) (when (eq? item 'c) item)) tbl)  ; when has implicit #<void>
=> '(#<void> #<void> c #<void>)

是时候做点黑客了。使用map + apply (如@WillNess的答案中所解释的),它具有在任何RxRS解释器中工作的优点,并且是最可移植的解决方案,因为它使用的是标准过程:

代码语言:javascript
运行
复制
(apply append (map (lambda (item) (if (eq? item 'c) (list item) '())) tbl))
=> '(c)

使用map + remove*

代码语言:javascript
运行
复制
(remove* (list (void)) (map (lambda (item) (when (eq? item 'c) item)) tbl))
=> '(c)

对于更改,不使用map的解决方案--改用foldr

代码语言:javascript
运行
复制
(foldr (lambda (item a) (append (if (eq? item 'c) (list item) '()) a)) '() tbl)
=> '(c)

当然,您可以只使用标准过程实现您自己版本的filter,这也可以移植到所有RxRS解释器中:

代码语言:javascript
运行
复制
(define (filter pred? lst)
  (cond ((null? lst)
         '())
        ((not (pred? (car lst)))
         (filter pred? (cdr lst)))
        (else
         (cons (car lst)
               (filter pred? (cdr lst))))))

(filter (lambda (item) (eq? item 'c)) tbl)
=> '(c)
票数 12
EN

Stack Overflow用户

发布于 2013-07-19 08:47:34

简单的“标准”技巧是

代码语言:javascript
运行
复制
(apply append (map (lambda(x)(if (eq? x 'c) (list x) '())) '(a b c d)))
;Value 12: (c)

返回(c)apply append ... map组合体在通用Lisp中被称为mapcan ("mapcan“表示"map和concatenate"):

代码语言:javascript
运行
复制
[1]> (mapcan #'(lambda(x)(if (eq x 'c) (list x))) '(a b c d))
(C)

麻省理工学院计划也有这个功能。

apply append将其参数列表的一个级别-- (apply append '((a) () (c) ())) == (append '(a) '() '(c) '()) -> (a c)。由于空列表消失了,所以它对于用map消除元素很有用。如果您有一个可用的filter (它不在R5RS中,但在SRFI1中),这将实现与SRFI1相同的效果。

它也可以用于其他效果,如加倍:

代码语言:javascript
运行
复制
[2]> (mapcan #'(lambda(x)(if (evenp x) (list x x))) '(1 2 3 4))
(2 2 4 4)

顺便说一句,mapcan是list monad的"bind“(带参数翻转),(apply append ...)是它的”联接“操作。事实上,对于任何一个单子,列表也是如此,bind m f == join (map f m)也是如此。

这也是Haskell的清单理解的基础:

代码语言:javascript
运行
复制
Prelude> [y | x<-[1,2,3,4], even x, y<-[x,x]]
[2,2,4,4]
票数 3
EN

Stack Overflow用户

发布于 2013-07-16 20:43:52

您没有提到您的计划版本/环境。假设您只有最基本的方案,那么很容易实现:

代码语言:javascript
运行
复制
(define (choose-if pred list)
  (let choosing ((list list) (rslt '()))
    (if (null? list)
        (reverse rslt)
        (choosing (cdr list)
                  (if (pred (car list))
                      (cons (car list) rslt)
                      rslt)))))

然后联系到:

代码语言:javascript
运行
复制
(define (choose item list)
  (choose-if (lambda (elt) (eq? item elt)) list))

(define (choose-if-not pred list)
  (choose-if (lambda (elt) (not (pred elt))) list))

和使用:

代码语言:javascript
运行
复制
> (choose 'c '(a b c d))
(c)

您还可以选择使用低级原语,如:

代码语言:javascript
运行
复制
(define (choose item list)
  (remq #f (map (lambda (elt) (eq? item elt)) list)))

代码语言:javascript
运行
复制
(define (choose item list)
   (remp (lambda (elt) (not (eq? item elt))) list))
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17680799

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档