33 accumulators polishing code functional data
play

33: Accumulators & Polishing code (Functional Data) - PowerPoint PPT Presentation

33: Accumulators & Polishing code (Functional Data) Accumulators Estimated Value and search subtrees Functional data structures Strategies we've seen so far "Strengthen the recursion": solve a more general problem


  1. 33: Accumulators & Polishing code (Functional Data) Accumulators Estimated Value and search subtrees Functional data structures

  2. Strategies we've seen so far • "Strengthen the recursion": solve a more general problem… • Often "add another argument • sometimes an extra argument is just a counter (today's quiz) or a yes/no toggle • sometimes more • "fancy censor starting with either * or +" vs "fancy censor" • bignum-add-with-carry rather than bignum-add • …to make your recursive result more useful to you as you construct the overall result • T oday's quiz! • Accumulators or other stored data to help with recursion • Reverse! (which also uses idea 1) • Divide and conquer (mergesort) • Break problem into manageable pieces (Rackette)

  3. Reverse a list, slow version OI. [3, 4, 1, 5, 6] RI. [4, 1, 5, 6] RR [6, 5, 1, 4] append a list containing the head of OI to the recursive result OR [6, 5, 1, 4, 3]

  4. Reverse a list, slow version /* reverse: list('a) => list('a) ** Input: a list of items ** Output: a list containing the same items, ** in reverse order */ let rec slowReverse: list('a) => list('a) = fun | [] => [] | [hd, ...tl] => slowReverse(tl) @ [hd]; Because append (@) takes time proportional to the length of the fjrst list, the runtime is in O(n => n^2).

  5. Improve reverse! /* reverseHelp: (list('a), list('a)) => list('a) ** Input: ** start, a list of items ** partial, a list to append to the reversed version of "start" ** Output: a list containing the items in "start" in reverse order, ** followed by those in "partial" */ let rec reverseHelp = ... let fastReverse: list('a) => list('a) = input => reverse_help(input, []); Run time of fastReverse is that of reverseHelp

  6. reverseHelp /* reverseHelp: (list('a), list('a)) => list('a) ** Input: ** start, a list of items ** partial, a list to append to the reversed version of "start" ** Output: a list containing the items in "start" in reverse order, ** followed by those in "partial" */ let rec reverseHelp = (start, partial) => switch(start) { | [] => partial | [hd, ... tl] => reverseHelp(tl, [hd, ...partial]) }; Runtime: linear in length of "start", so that fastReverse is linear-time.

  7. What makes reverseHelp work? • Secret sauce: save your "partial work" (the reverse of the initial items in the list) using a second argument, one in which you "accumulate" results. • This extra argument is called an "accumulator" • This is also what goes on "fold", for instance. • Idea is used repeatedly in this week's HW.

  8. Quiz • let mapi: ((int, 'a) => 'b, list('a)) => list('b); Same as List.map, but the function is applied to the index of the element as fjrst argument (counting from 0), and the element itself as second argument. mapi( (x, y) => (x, y), ["a", "b", "c"]) produces [(0, "a"), (1, "b"), (2, "c")] mapi( (x, y) => x*y, [3, 1, 4]) produces [0, 1, 8]

  9. Recursion Diagram OI "+",[1, 3, 4] RI "+",[3, 4] RO [3, 5] uh…add one to each item in RO, then cons on 1 + 0? That won't work when it's "*" instead of "+" I really needed to add 1 to 3 and 2 to 4 OO [1, 4, 6]

  10. Strengthen the recursion! let mapi = (f, alod) => mapiHelper(f, alod, 0); • This helper simply works like mapi, but "counting up" from the third argument, rather than from 0. • Type signature for mapiHelper • Code for mapiHelper let rec mapiHelper = (f, alod, n) => switch(alod) { | [] => ??? /* JUST THESE | [hd, ... tl] => [f(n, hd), ... ???] ** TWO LINES */ };

  11. Complicated programs are diffjcult to debug and maintain

  12. • It's always worth splitting into subtasks • It's always worth cleaning up and simplifying code • "Polished" code is nice to look at • Makes us more inclined to jump in and debug it

  13. An Example (courtesy of a fellow student; code slightly edited)

  14. let rec iroot: (int, int, int => int) => int = |x when x < 0 => { (n, m, proc) =>{ if(procApplyN > 0){ let newBound = (n+m)/2; if(newBound-n == 1){ let procApply = proc(newBound); n let procApplyN = proc(n); } switch(procApply){ else iroot(n, newBound, proc) |x when x > 0 => { } else if (procApplyN < 0) { if(procApplyN > 0){ 40 lines! if(newBound-n == 1){ if(newBound-n == 1){ n n } } else iroot(newBound, m, proc) else iroot(newBound, m, proc) } else if (procApplyN < 0) { } else { if(newBound-n == 1){ newBound n } } } else iroot(n, newBound, proc) } else { |0 => newBound newBound | _ => failwith("Incomplete Match Case error") } }; } }

  15. let rec iroot: (int, int, int => int) => int = |x when x < 0 => { (n, m, proc) =>{ if(procApplyN > 0){ let newBound = (n+m)/2; if(newBound-n == 1){ let procApply = proc(newBound); n let procApplyN = proc(n); } switch(procApply){ else iroot(n, newBound, proc) |x when x > 0 => { } else if (procApplyN < 0) { if(procApplyN > 0){ if(newBound-n == 1){ if(newBound-n == 1){ n n } } else iroot(newBound, m, proc) else iroot(newBound, m, proc) } else { } else if (procApplyN < 0) { newBound if(newBound-n == 1){ } n } } |0 => newBound else iroot(n, newBound, proc) | _ => failwith("Incomplete Match Case error") } else { }; newBound } } }

  16. let rec iroot: (int, int, int => int) => int = |x when x < 0 => { (a, b, proc) =>{ if(procApplyN > 0){ let newBound = (a+b)/2; if(newBound-a == 1){ let procApply = proc(newBound); a let procApplyN = proc(a); } switch(procApply){ else iroot(a, newBound, proc) |x when x > 0 => { } else if (procApplyN < 0) { if(procApplyN > 0){ if(newBound-a == 1){ if(newBound-a == 1){ a a } } else iroot(newBound, b, proc) else iroot(newBound, b, proc) } else { } else if (procApplyN < 0) { newBound if(newBound-a == 1){ } a } } |0 => newBound else iroot(a, newBound, proc) | _ => failwith("Incomplete Match Case error") } else { }; newBound } } }

  17. let rec iroot: (int, int, int => int) => int = |x when x < 0 => { (a, b, proc) =>{ if(procApplyN > 0){ let newBound = (a+b)/2; if(newBound-a == 1){ let procApply = proc(newBound); a let procApplyN = proc(a); } switch(procApply){ else iroot(a, newBound, proc) |x when x > 0 => { } else if (procApplyN < 0) { if(procApplyN > 0){ if(newBound-a == 1){ if(newBound-a == 1){ a a } } else iroot(newBound, b, proc) else iroot(newBound, b, proc) } else { } else if (procApplyN < 0) { newBound if(newBound-a == 1){ } a } } |0 => newBound else iroot(a, newBound, proc) | _ => failwith("Incomplete Match Case error") } else { }; newBound } } }

  18. let rec iroot: (int, int, int => int) => int = | x when x < 0 => { (a, b, proc) =>{ if (procApplyN > 0){ let newBound = (a + b) / 2; if (newBound - a == 1){ let procApply = proc(newBound); a let procApplyN = proc(a); } switch (procApply){ else iroot(a, newBound, proc) | x when x > 0 => { } else if (procApplyN < 0) { if (procApplyN > 0){ if (newBound - a == 1){ if (newBound - a == 1){ a a } } else iroot(newBound, b, proc) else iroot(newBound, b, proc) } else { } else if (procApplyN < 0) { newBound if (newBound - a == 1){ } a } } | 0 => newBound else iroot(a, newBound, proc) | _ => failwith("Incomplete Match Case error") } else { }; newBound } } }

  19. let rec iroot: (int, int, int => int) => int = | x when x < 0 => { (a, b, proc) =>{ if (procApplyN > 0){ let newBound = (a + b) / 2; if (newBound - a == 1){ let procApply = proc(newBound); a let procApplyN = proc(a); } switch (procApply){ else iroot(a, newBound, proc) | x when x > 0 => { } else if (procApplyN < 0) { if (procApplyN > 0){ if (newBound - a == 1){ if (newBound - a == 1){ a a } } else iroot(newBound, b, proc) else iroot(newBound, b, proc) } else { } else if (procApplyN < 0) { newBound if (newBound - a == 1){ } a } } | 0 => newBound else iroot(a, newBound, proc) | _ => failwith("Incomplete Match Case error") } else { }; newBound } } }

  20. let rec iroot: (int, int, int => int) => int = | x when x < 0 => { (a, b, proc) =>{ if (leftVal > 0){ let mid = (a + b) / 2; if (mid - a == 1){ let midVal = proc(mid); a let leftVal = proc(a); } switch (midVal){ else iroot(a, mid, proc) | x when x > 0 => { } else if (leftVal < 0) { if (leftVal > 0){ if (mid - a == 1){ if (mid - a == 1){ a a } } else iroot(mid, b, proc) else iroot(mid, b, proc) } else { } else if (leftVal < 0) { mid if (mid - a == 1){ } a } } | 0 => mid else iroot(a, mid, proc) | _ => failwith("Incomplete Match Case error") } else { }; mid } } }

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend