Scheme折叠图和过滤函数

时间:2013-02-03 01:37:41

标签: list filter functional-programming scheme predicate

我正在学习如何在方案中使用高阶函数。我明白了使用高阶函数,但是我在使用它们时遇到了麻烦。对于这个学习练习,我宁愿只使用滤镜,折叠和/或贴图的某种组合。

例如,我想构建两个列表之间的集合差异,将它们称为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“不等于”

  1. 对于A中的每个a和B中的b,评估表达式:(neq? a b)

    对于a = 1,我们有:

    (和(neq?1 5)(neq?1 7)(neq?1 9)(neq?1 1)(neq?1 6))

  2. 如果此表达式为true,则a将进入新列表;否则不要添加到新列表。在我们的示例中,(neq? 1 1)的计算结果为false,因此我们不会将1添加到新列表中。

  3. 我的整个程序几乎都依赖于1,这就是我遇到麻烦的地方。

    1. 如何执行第1步?
    2. 我在步骤1中看到我需要mapfold函数的某种组合,但如何分发and a neq b
    3. 编辑这是我最接近的样本:

      (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中相同位置/索引处的元素执行此操作。

      非常感谢所有帮助!

4 个答案:

答案 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))))