【问题标题】:Implementing "Accumulate" Function in Scheme在 Scheme 中实现“累加”功能
【发布时间】:2016-09-24 00:08:14
【问题描述】:

现在,我一直在尝试实现 Accumulate 函数几个星期。我已经正确实现了一个“映射”函数,它遍历一个列表并在每个元素上运行一个函数。

我正在使用这个函数来实现“累积”

   (define accumulate
  (lambda (op base func ls)
    (if(null? ls)
       ls
   (cond (not (null? (cdr ls)) (op base (map func ls) (accumulate op base func (cdr ls))))
       (op base (map func ls) (op base (func(car ls))))
   )
     )))
    ;It gets to a point (the last element) after applying the map function to each element,
    ;where it is '(number) instead of an expected "number" (outside of () ). I cannot figure out
    ;how to circumvent this.

我一直不知道如何做到这一点。这样做的正确方法是什么?

预期的结果是:

; accumulate: combines using OP the values of a list LS after mapping a function FUNC on it
;    (accumulate + 0 sqr '(1 2 3)) => 14
;    (accumulate * 1 sqr '(1 2 3)) => 36
;

【问题讨论】:

  • 我认为您的cond 声明不正确。 (cond ((not (null? (cdr ls))) (op base ...
  • accumulate 的输出到底应该是什么?请提供具有预期输出的示例输入
  • 另外,你为什么需要map?您确定您的输入是 lists 的列表吗?

标签: list scheme map-function accumulate


【解决方案1】:

你想实现一个适用于列表的折叠过程,你不需要使用map,只需依次处理每个元素。这更像是:

(define accumulate
  (lambda (op base func ls)
    (if (null? ls)
        base
        (op (func (car ls))
            (accumulate op base func (cdr ls))))))

例如:

(accumulate + 0 sqr '(1 2 3))
=> 14

(accumulate * 1 sqr '(1 2 3))
=> 36

【讨论】:

  • 感谢您的建议。添加了预期输出的副本以供参考。
  • @ChristopherKelly 现在不一样了!看?你根本不需要map
【解决方案2】:

可以使用map 实现您的accumulate(1) 既有趣又无利润:

(define (accumulate op base func ls)
  (define (butlast xs) 
      (reverse (cdr (reverse xs))))
  (let ((xs (map list ls)))       ; box'em up
    (for-each
       (lambda (a1 x)
         (let ((a2  (op (car a1) (func (car x))) ))
            (set-car! x a2)))
       (butlast (cons (list base) xs))
       xs)
    (caar (reverse xs))))         ; last

(display (accumulate + 0 (lambda (x) (* x x)) (list 1 2 3 4)))

;   0 1 5 14
;   1 2 3 4   => 30
; 0 1 5 14

(1)(嗯,for-each,这在很大程度上类似于map,但确保了函数应用在参数列表中的从左到右的顺序,这是必不可少的……或者我们可以使用 SRFI-1 中的 map-in-order,它的额外优势是无需调用 butlast

这在 R5RS 方案中模拟(带有明显的扭曲),旧时的惰性流编程定义

accumulate op base ls  =  last xs
  where
      xs = [base, ...map op xs ls]

~> accumulate (+) 0 (map (^2) [1,2,3,4])
30
  
;;   0 a b c d   +
;;   1 4 9 16    =    d
;; 0 a b c d

(在伪代码中)当它沿着列表移动时,它还会在过去一个当前列表节点“写入”累积结果。这是actually known as scanl,例如Haskell,并从该列表中取出最后一个结果使其成为foldl(左侧折叠)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-04
    • 2017-03-30
    • 2014-03-08
    • 1970-01-01
    • 2015-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多