我正在学习如何在方案中使用高阶函数。我明白了使用高阶函数,但是我在使用它们时遇到了麻烦。对于这个学习练习,我宁愿只使用滤镜,折叠和/或贴图的某种组合。
例如,我想构建两个列表之间的集合差异,将它们称为A和B.我将集合差异定义为x,使得x是A的元素,但x不是B的元素。我只想要使用函数map,filter和fold。例如:
设A =(1 8 6 2)
设B =(5 7 9 1 6)
A和B的设定差异为(8 2)
想法是通过迭代A的元素并查看A的元素是否等于B的元素来构造新列表,如果是,则不将a添加到新列表中;否则添加到新列表。
我的算法想法是这样的:
让neq“不等于”
对于A中的每个a和B中的b,评估表达式:(neq? a b)
对于a = 1,我们有:
(和(neq?1 5)(neq?1 7)(neq?1 9)(neq?1 1)(neq?1 6))
如果此表达式为true,则a将进入新列表;否则不要添加到新列表。在我们的示例中,(neq? 1 1)
的计算结果为false,因此我们不会将1添加到新列表中。
我的整个程序几乎都依赖于1,这就是我遇到麻烦的地方。
map
和fold
函数的某种组合,但如何分发and a neq b
?编辑这是我最接近的样本:
(fold-right (trace-lambda buggy (a b c) (and (neq? a b))) #t A B)
|(buggy 3 5 #t)
|#t
|(buggy 2 4 #t)
|#t
|(buggy 1 1 #t)
|#f
#f
上面显示了我的匿名函数试图执行(和(neq?a b))链的痕迹。但是,它仅对A和B中相同位置/索引处的元素执行此操作。
非常感谢所有帮助!
答案 0 :(得分:3)
member
的简化版本很容易使用fold
实现,当然:
(define (member x lst)
(fold (lambda (e r)
(or r (equal? e x)))
#f lst))
现在,有了这个,其余的都是微不足道的:
(define (difference a b)
(filter (lambda (x)
(not (member x b)))
a))
如果你想将所有这些合并到一个功能中(使用你的neq?
),你可以这样做:
(define (difference a b)
(filter (lambda (x)
(fold (lambda (e r)
(and r (neq? e x)))
#t b))
a))
答案 1 :(得分:3)
在Haskell中,由于懒惰的评估,fold
能够进行短路评估。
但是在Scheme中这是不可能的。这就是为什么在Racket 中,例如,为ormap
提供了一个特殊功能, 能够进行短路评估。 IOW它是一种特殊的fold
,必须在Scheme中明确定义并单独定义,因为Scheme不是懒惰的。因此,根据您的条件,我认为可以将其用作特殊类型的fold
。
使用它,我们得到
(define (diff xs ys)
(filter
(lambda (y)
(not (ormap (lambda (x) (equal? x y)) ; Racket's "ormap"
xs)))
ys))
如果您的元素可以订购,最好将这些集合维护为有序(升序)列表;然后diff
可以更有效地实施,比较两个列表中的头元素并相应地推进,以线性时间工作。
答案 2 :(得分:1)
使用球拍:
(define A '(1 8 6 2))
(define B '(5 7 9 1 6))
(filter-not (lambda (x) (member x B)) A)
==> '(8 2)
答案 3 :(得分:1)
当然,Scheme可以在member
之上实现fold
在第一场比赛中发生短路:
(define (member x lst)
(call-with-current-continuation
(lambda (return)
(fold (lambda (e r)
(if (equal? e x)
(return #t)
r))
#f lst))))