问题
I've been hung on trying to implement an Accumulate function for a couple weeks, now. I have properly implemented a "Map" function, that iterates across a list and runs a function on each element.
I am using this function to implement "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.
I'm stuck on how to get this right. What is the right way to do this?
The intended result is:
; 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
;
回答1:
You want to implement a folding procedure that works for a list, you don't need to use map
, simply process each element in turn. This is more like it:
(define accumulate
(lambda (op base func ls)
(if (null? ls)
base
(op (func (car ls))
(accumulate op base func (cdr ls))))))
For example:
(accumulate + 0 sqr '(1 2 3))
=> 14
(accumulate * 1 sqr '(1 2 3))
=> 36
回答2:
You can implement your accumulate
with map
, for fun and no profit:
(define accumulate
(lambda (op base func ls)
(let ((z (map list ls))) ; box'em
(car (reverse ; last
(map (lambda (x y)
(let ((acc (op (car x) (func (car y)) )))
(set-car! y acc)
acc))
(reverse (cdr (reverse ; bulast
(cons (list base) z))))
z))))))
(display (accumulate + 0 (lambda(x)(* x x)) (list 1 2 3 4)))
; 0 1 2 3
; 1 2 3 4 => 30
This emulates (with the obvious twist), in r5rs Scheme, the old-time lazy stream programming definition
accumulate op base ls = last z
where
z = base : zipWith op z ls -- (:) is cons
~> accumulate (+) 0 (map (^2) [1..4])
30
-- 0 a b c d +
-- 1 4 9 16 =
-- 0 a b c d
which too "writes" the accumulated result at one-past-current list node, as it moves along the lists. This is actually known as scanl in e.g. Haskell, and taking the last result from that list makes it foldl
(the left fold).
来源:https://stackoverflow.com/questions/39671186/implementing-accumulate-function-in-scheme