Skip to content

Commit

Permalink
Merge pull request fpinscala#384 from GlenKPeterson/patch-1
Browse files Browse the repository at this point in the history
Added foldLeftViaFoldRight_1
  • Loading branch information
pchiusano committed Mar 19, 2015
2 parents 91f3aaf + 9b04ac4 commit 61d641c
Showing 1 changed file with 102 additions and 1 deletion.
103 changes: 102 additions & 1 deletion answerkey/datastructures/13.answer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,105 @@ def foldRightViaFoldLeft_1[A,B](l: List[A], z: B)(f: (A,B) => B): B =
foldLeft(l, (b:B) => b)((g,a) => b => g(f(a,b)))(z)

def foldLeftViaFoldRight[A,B](l: List[A], z: B)(f: (B,A) => B): B =
foldRight(l, (b:B) => b)((a,g) => b => g(f(b,a)))(z)
foldRight(l, (b:B) => b)((a,g) => b => g(f(b,a)))(z)

// Here is the same function with much more description
def foldLeftViaFoldRight_1[A,B](as: List[A], outerIdent: B)(combiner: (B, A) => B): B = {

// foldLeft processes items in the reverse order from foldRight. It's
// cheating to use reverse() here because that's implemented in terms of
// foldLeft! Instead, wrap each operation in a simple identity function to
// delay evaluation until later and stack (nest) the functions so that the
// order of application can be reversed. We'll call the type of this
// particular identity/delay function BtoB so we aren't writing B => B
// everywhere:
type BtoB = B => B

// Here we declare a simple instance of BtoB according to the above
// description. This function will be the identity value for the inner
// foldRight.
def innerIdent:BtoB = (b:B) => b

// For each item in the 'as' list (the 'a' parameter below), make a new
// delay function which will use the combiner function (passed in above)
// when it is evaluated later. Each new function becomes the input to the
// previous function (delayFunc).
//
// This much is just the type signature
// ,-------^-------.
def combinerDelayer:(A, BtoB) => BtoB =
(a: A, delayFunc: BtoB) => (b:B) => delayFunc(combiner(b, a))
// `----------v---------' `----------------v---------------'
// Paramaters The returned function

// Pass the original list 'as', plus the simple identity function and the
// new combinerDelayer to foldRight. This will create the functions for
// delayed evaluation with an combiner inside each one, but will not
// apply any of those functions.
def go:BtoB = foldRight(as, innerIdent)(combinerDelayer)

// This forces all the evaluations to take place
go(outerIdent)
}

/*
Here is a sample run for further illustration purposes
foldLeftViaFoldRight_1(List(1,2,3), Nil:List[Int])((b:B, a:A) => Cons(a, b))
Becomes:
foldRight(List(1,2,3), innerIdent)(combinerDelayer)(Nil)
Becomes:
def delay3(b:B) = innerIdent(combiner(b, 3))
def delay2(b:B) = delay3(combiner(b, 2))
def delay1(b:B) = delay2(combiner(b, 1))
delay1(Nil)
Becomes:
def delay3(b:B) = innerIdent(combiner(b, 3))
def delay2(b:B) = delay3(combiner(b, 2))
delay2(combiner(Nil, 1))
Becomes:
def delay3(b:B) = innerIdent(combiner(b, 3))
delay3(combiner(combiner(Nil, 1), 2))
Becomes:
innerIdent(combiner(combiner(combiner(Nil, 1), 2), 3))
Becomes:
combiner(combiner(combiner(Nil, 1), 2), 3)
Becomes:
combiner(combiner(Cons(1,Nil), 2), 3)
Becomes:
combiner(Cons(2,Cons(1,Nil)), 3)
Becomes:
Cons(3,Cons(2,Cons(1,Nil)))
Voila!
Alternate Route:
def delay3(b:B) = innerIdent(combiner(b, 3))
def delay2(b:B) = delay3(combiner(b, 2))
def delay1(b:B) = delay2(combiner(b, 1))
delay1(Nil)
Becomes:
def delay2(b:B) = innerIdent(combiner(combiner(b, 2), 3))
def delay1(b:B) = delay2(combiner(b, 1))
delay1(Nil)
Equivalent:
def delay1(b:B) = innerIdent(combiner(combiner(combiner(b, 1), 2), 3))
delay1(Nil)
Equivalent:
((b:B) => innerIdent(combiner(combiner(combiner(b, 1), 2), 3)))(Nil)
Equivalent:
innerIdent(combiner(combiner(combiner(Nil, 1), 2), 3))
*/

0 comments on commit 61d641c

Please sign in to comment.