Reputation: 117
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
;
Upvotes: 0
Views: 3868
Reputation: 71075
You can implement your accumulate
with map
,(1) for fun and no profit:
(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)(well, for-each
, which is largely similar to map
but ensures the left-to-right order of function application across the argument lists, which is essential here... or we could use map-in-order
from SRFI-1 which has the additional advantage that calling butlast
becomes unnecessary).
This emulates (with the obvious twist), in R5RS Scheme, the old-time lazy stream programming definition of
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
(in pseudocode) which also "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).
Upvotes: 1
Reputation: 236034
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
Upvotes: 3