[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
SRFI-1's fold is not fold-left!
Dear Manuel, et.al.,
While translating some OCaml code I have come across the following
discrepancy. Although it is known, it is worthwhile to mention it, I
think. The SRFI-1's fold is not actually a fold-left (it is mentioned
in passing in SRFI-1 itself that F's args are flipped w.r.t. MIT-Scheme
and Haskell).
To set things straight, I think, it would make sense to add a fold-left
function to Bigloo (and maybe to the SRFI-1 itself). An example patch is
attached (fold-left)
Kind regards,
Pjotr
P.S. Also attached is a comparable patch for SLIB.
# HG changeset patch
# Parent a3c09eae22b731dc89af30c71769fc1ff4b2866e
diff -r a3c09eae22b7 api/srfi1/src/Llib/srfi1.srfi
--- a/api/srfi1/src/Llib/srfi1.srfi Wed Oct 31 09:27:15 2012 +0100
+++ b/api/srfi1/src/Llib/srfi1.srfi Wed Oct 31 09:54:10 2012 +0100
@@ -835,8 +835,21 @@
(let recur ((seed seed))
(if (p seed) '()
(cons (f seed) (recur (g seed)))))))
-
+; real fold-left (ala Haskell & OCaml)
+(define (fold-left kons knil lis1 . lists)
+ (check-arg procedure? kons fold-left)
+ (if (pair? lists)
+ (let lp ((lists (cons lis1 lists)) (ans knil)) ; N-ary case
+ (receive (cars cdrs) (%cars+cdrs lists)
+ (if (null? cars) ans ; Done.
+ (lp cdrs (apply kons ans cars)))))
+
+ (let lp ((lis lis1) (ans knil)) ; Fast path
+ (if (null-list? lis) ans
+ (lp (cdr lis) (kons ans (car lis)))))))
+
+; fold-left with flipped args (kept for compatibility purposes)
(define (fold kons knil lis1 . lists)
(check-arg procedure? kons fold)
(if (pair? lists)
@@ -875,6 +888,20 @@
(let recur ((lis lis1)) ; Fast path
(if (null-list? lis) zero (f lis (recur (cdr lis)))))))
+; This one is easier that fold-left, surprisingly...
+(define (pair-fold-left f zero lis1 . lists)
+ (check-arg procedure? f pair-fold-left)
+ (if (pair? lists)
+ (let lp ((lists (cons lis1 lists)) (ans zero)) ; N-ary case
+ (let ((tails (%cdrs lists)))
+ (if (null? tails) ans
+ (lp tails (apply f ans lists)))))
+
+ (let lp ((lis lis1) (ans zero))
+ (if (null-list? lis) ans
+ (let ((tail (cdr lis))) ; Grab the cdr now,
+ (lp tail (f ans lis)))))))
+
(define (pair-fold f zero lis1 . lists)
(check-arg procedure? f pair-fold)
(if (pair? lists)
@@ -897,6 +924,12 @@
(if (null-list? lis) ridentity
(fold f (car lis) (cdr lis))))
+; use fold-left rather than fold...
+(define (reduce-left f ridentity lis)
+ (check-arg procedure? f reduce-left)
+ (if (null-list? lis) ridentity
+ (fold-left f (car lis) (cdr lis))))
+
(define (reduce-right f ridentity lis)
(check-arg procedure? f reduce-right)
(if (null-list? lis) ridentity
--- srfi-1.scm 2008-12-08 03:29:50.000000000 +0100
+++ srfi-1.scm 2012-10-31 10:01:58.512712354 +0100
@@ -234,6 +234,13 @@
z
(apply fold (cons* f (apply f (append! (map car l) (list z)))
(map cdr l)))))
+
+(define (fold-left f z l1 . l)
+ (set! l (cons l1 l))
+ (if (any null? l)
+ z
+ (apply fold-left (cons* f (apply f (append! (list z) (map car l)))
+ (map cdr l)))))
;;@args kons knil clist1 clist2 ...
(define (fold-right f z l1 . l)
(set! l (cons l1 l))
@@ -247,6 +254,11 @@
z
(let ((tail (cdr l)))
(pair-fold f (f l z) tail))))
+(define (pair-fold-left f z l) ;XXX should be multi-arg
+ (if (null? l)
+ z
+ (let ((tail (cdr l)))
+ (pair-fold-left f (f z l) tail))))
;;@args kons knil clist1 clist2 ...
(define (pair-fold-right f z l) ;XXX should be multi-arg
(if (null? l)
@@ -264,6 +276,17 @@
ridentity
(fold f (car list) (cdr list)))))
args))))
+
+(define reduce-left
+ (let ((comlist-reduce reduce-left))
+ (lambda args
+ (apply (if (= 2 (length args))
+ comlist-reduce
+ (lambda (f ridentity list)
+ (if (null? list)
+ ridentity
+ (fold-left f (car list) (cdr list)))))
+ args))))
(define (reduce-right f ridentity list)
(if (null? list)