Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
425 views
in Technique[技术] by (71.8m points)

scheme - Expanded form of fold in Racket

Example from http://www.cse.unsw.edu.au/~en1000/haskell/hof.html :

(foldr / 7 (list 34 56 12 4 23))
(foldl / 7 (list 34 56 12 4 23))

Output in Racket:

5 193/196
5 193/196

What would be the full (expanded) form of foldl and foldr in this case? It is not the following:

> (/ (/ (/ (/ (/ 7 34) 56) 12) 4) 23)
1/300288

Edit: I have modified above question since implementation of fold in Racket vs Haskell has been explained in another question Why is foldl defined in a strange way in Racket?.

Edit: If I understand the answers clearly, the expanded form can be shown very clearly using "threading" module, where statements appear in order of execution (_ indicates output of previous statement):

foldl:

(require threading)
; expanded form of (foldl / 7 (list 34 56 12 4 23))
; FROM LEFT TO RIGHT: 
(~> 7
    (/ 34 _)
    (/ 56 _)
    (/ 12 _)
    (/ 4  _)
    (/ 23 _) )

foldr:

; expanded form of (foldr / 7 (list 34 56 12 4 23))
; FROM RIGHT TO LEFT: 
(~> 7
    (/ 23 _)
    (/ 4  _)
    (/ 12 _)
    (/ 56 _)
    (/ 34 _) )

The output in both cases is same:

5 193/196
5 193/196

It gives correct answers (which are different for foldl and foldr) in following example also:

; FROM LEFT TO RIGHT:
(foldl - 0 '(1 2 3 4))
(~> 0
    (- 1 _)  ; 1-0=1
    (- 2 _)  ; 2-1=1
    (- 3 _)  ; 3-1=2
    (- 4 _)) ; 4-2=2

; FROM RIGHT TO LEFT: 
(foldr - 0 '(1 2 3 4))
(~> 0
    (- 4 _)  ; 4-0=4
    (- 3 _)  ; 3-4=-1
    (- 2 _)  ; 2-(-1)=3
    (- 1 _)) ; 1-3=-2

Output:

2
2
-2
-2

In common language, it seems:

The sent function takes 2 arguments, 

the first argument is from the list, one after the other 
(left to right or right to left depending on foldl and foldr), 

the second argument is init first and 
then the output of previous calculation.
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

In DrRacket, press the right mouse button on foldl and choose "Open defining file" In the provide list right click again and choose "Jump to the next bound occurance". You'll see this:

(define foldl
  (case-lambda
    [(f init l)
     (check-fold 'foldl f init l null)
     (let loop ([init init] [l l])
       (if (null? l) init (loop (f (car l) init) (cdr l))))]
    [(f init l . ls)
     (check-fold 'foldl f init l ls)
     (let loop ([init init] [ls (cons l ls)])
       (if (pair? (car ls)) ; `check-fold' ensures all lists have equal length
           (loop (apply f (mapadd car ls init)) (map cdr ls))
           init))]))

However since you only have one list it's the first term in case lambda that is the current and the fist line checks arguments and throw exceptions. You can simplify it to:

(define (foldl f init l)
  (let loop ([init init] [l l])
    (if (null? l)
        init
        (loop (f (car l) init) (cdr l))))

Using substitution rules:

(foldl / 7 '(34 56 12 4 23))                                  ;==>
(loop 7 '(34 56 12 4 23))                                     ;==>
(loop (/ (car '(34 56 12 4 23)) 7) (cdr '(34 56 12 4 23)))    ;==>
(loop (/ (car '(56 12 4 23)) (/ (car '(34 56 12 4 23)) 7)) (cdr '(56 12 4 23)))    ;==>
(loop (/ (car '(12 4 23)) (/ (car '(56 12 4 23)) (/ (car '(34 56 12 4 23)) 7))) (cdr '(12 4 23)))    ;==>
(loop (/ (car '(4 23)) (/ (car '(12 4 23)) (/ (car '(56 12 4 23)) (/ (car '(34 56 12 4 23)) 7)))) (cdr '(4 23)))    ;==>
(loop (/ (car '(23)) (/ (car '(4 23)) (/ (car '(12 4 23)) (/ (car '(56 12 4 23)) (/ (car '(34 56 12 4 23)) 7))))) (cdr '(23)))    ;==>
(/ (car '(23)) (/ (car '(4 23)) (/ (car '(12 4 23)) (/ (car '(56 12 4 23)) (/ (car '(34 56 12 4 23)) 7)))))    ;==>
(/ 23 (/ 4 (/ 12 (/ 56 (/ 34 7)))))    ;==>
5 193/196

I'll leave the foldr one as an exercise.

About folds and standards

The folds in #!racket are racket specific. In Scheme, more precisely #!r6rs you have fold-left and fold-right and unlike #!racket the argument order from a left to a right changes making it more similar to the *new Haskell version.

SRFI-1 list library uses the names fold and foldr and expect the same argument order for both, just like #!racket. SRFI-1 also supports different length lists and stops at the shortest one so it is the one with most features. SRFI-1 can be included in both #!racket with (require srfi/1)and with #!r6rs. (import (rnrs :1))


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...