From 9b04ac4c45a99dcfa21fb547af0770637b5fc90c Mon Sep 17 00:00:00 2001 From: "Glen K. Peterson" Date: Mon, 23 Feb 2015 23:15:37 -0500 Subject: [PATCH] Added foldLeftViaFoldRight_1 I needed a lot more detail in order to understand the solution to foldLeftViaFoldRight, so I added foldLeftViaFoldRight_1 which is functionally the same, but with additional details (longer variable names, intermediate types and variables, comments, and a sample run). There may be a better intermediate step in the sample run to illustrate how the delay functions are combined. I also may have swapped Normal and Applicative order evaluation by mistake at some point in that comment, but it still helped me visualize how this might play out. I thought I'd offer it here in case other people might find it helpful too. --- answerkey/datastructures/13.answer.scala | 103 ++++++++++++++++++++++- 1 file changed, 102 insertions(+), 1 deletion(-) diff --git a/answerkey/datastructures/13.answer.scala b/answerkey/datastructures/13.answer.scala index 9f1406d4de..115c0e2c6f 100644 --- a/answerkey/datastructures/13.answer.scala +++ b/answerkey/datastructures/13.answer.scala @@ -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) \ No newline at end of file + 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)) +*/