33: Accumulators & Polishing code (Functional Data)
Accumulators Estimated Value and search subtrees Functional data structures
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
Accumulators Estimated Value and search subtrees Functional data structures
RR [6, 5, 1, 4] append a list containing the head of OI to the recursive result OR [6, 5, 1, 4, 3]
/* 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).
/* 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
/* 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.
the initial items in the list) using a second argument,
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]
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]
let mapi = (f, alod) => mapiHelper(f, alod, 0);
third argument, rather than from 0.
let rec mapiHelper = (f, alod, n) => switch(alod) { | [] => ??? /* JUST THESE | [hd, ... tl] => [f(n, hd), ... ???] ** TWO LINES */ };
let rec iroot: (int, int, int => int) => int = (n, m, proc) =>{ let newBound = (n+m)/2; let procApply = proc(newBound); let procApplyN = proc(n); switch(procApply){ |x when x > 0 => { if(procApplyN > 0){ if(newBound-n == 1){ n } else iroot(newBound, m, proc) } else if (procApplyN < 0) { if(newBound-n == 1){ n } else iroot(n, newBound, proc) } else { newBound } }
|x when x < 0 => { if(procApplyN > 0){ if(newBound-n == 1){ n } else iroot(n, newBound, proc) } else if (procApplyN < 0) { if(newBound-n == 1){ n } else iroot(newBound, m, proc) } else { newBound } } |0 => newBound | _ => failwith("Incomplete Match Case error") }; }
40 lines!
let rec iroot: (int, int, int => int) => int = (n, m, proc) =>{ let newBound = (n+m)/2; let procApply = proc(newBound); let procApplyN = proc(n); switch(procApply){ |x when x > 0 => { if(procApplyN > 0){ if(newBound-n == 1){ n } else iroot(newBound, m, proc) } else if (procApplyN < 0) { if(newBound-n == 1){ n } else iroot(n, newBound, proc) } else { newBound } } |x when x < 0 => { if(procApplyN > 0){ if(newBound-n == 1){ n } else iroot(n, newBound, proc) } else if (procApplyN < 0) { if(newBound-n == 1){ n } else iroot(newBound, m, proc) } else { newBound } } |0 => newBound | _ => failwith("Incomplete Match Case error") }; }
let rec iroot: (int, int, int => int) => int = (a, b, proc) =>{ let newBound = (a+b)/2; let procApply = proc(newBound); let procApplyN = proc(a); switch(procApply){ |x when x > 0 => { if(procApplyN > 0){ if(newBound-a == 1){ a } else iroot(newBound, b, proc) } else if (procApplyN < 0) { if(newBound-a == 1){ a } else iroot(a, newBound, proc) } else { newBound } } |x when x < 0 => { if(procApplyN > 0){ if(newBound-a == 1){ a } else iroot(a, newBound, proc) } else if (procApplyN < 0) { if(newBound-a == 1){ a } else iroot(newBound, b, proc) } else { newBound } } |0 => newBound | _ => failwith("Incomplete Match Case error") }; }
let rec iroot: (int, int, int => int) => int = (a, b, proc) =>{ let newBound = (a+b)/2; let procApply = proc(newBound); let procApplyN = proc(a); switch(procApply){ |x when x > 0 => { if(procApplyN > 0){ if(newBound-a == 1){ a } else iroot(newBound, b, proc) } else if (procApplyN < 0) { if(newBound-a == 1){ a } else iroot(a, newBound, proc) } else { newBound } } |x when x < 0 => { if(procApplyN > 0){ if(newBound-a == 1){ a } else iroot(a, newBound, proc) } else if (procApplyN < 0) { if(newBound-a == 1){ a } else iroot(newBound, b, proc) } else { newBound } } |0 => newBound | _ => failwith("Incomplete Match Case error") }; }
let rec iroot: (int, int, int => int) => int = (a, b, proc) =>{ let newBound = (a + b) / 2; let procApply = proc(newBound); let procApplyN = proc(a); switch (procApply){ | x when x > 0 => { if (procApplyN > 0){ if (newBound - a == 1){ a } else iroot(newBound, b, proc) } else if (procApplyN < 0) { if (newBound - a == 1){ a } else iroot(a, newBound, proc) } else { newBound } } | x when x < 0 => { if (procApplyN > 0){ if (newBound - a == 1){ a } else iroot(a, newBound, proc) } else if (procApplyN < 0) { if (newBound - a == 1){ a } else iroot(newBound, b, proc) } else { newBound } } | 0 => newBound | _ => failwith("Incomplete Match Case error") }; }
let rec iroot: (int, int, int => int) => int = (a, b, proc) =>{ let newBound = (a + b) / 2; let procApply = proc(newBound); let procApplyN = proc(a); switch (procApply){ | x when x > 0 => { if (procApplyN > 0){ if (newBound - a == 1){ a } else iroot(newBound, b, proc) } else if (procApplyN < 0) { if (newBound - a == 1){ a } else iroot(a, newBound, proc) } else { newBound } } | x when x < 0 => { if (procApplyN > 0){ if (newBound - a == 1){ a } else iroot(a, newBound, proc) } else if (procApplyN < 0) { if (newBound - a == 1){ a } else iroot(newBound, b, proc) } else { newBound } } | 0 => newBound | _ => failwith("Incomplete Match Case error") }; }
let rec iroot: (int, int, int => int) => int = (a, b, proc) =>{ let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); switch (midVal){ | x when x > 0 => { if (leftVal > 0){ if (mid - a == 1){ a } else iroot(mid, b, proc) } else if (leftVal < 0) { if (mid - a == 1){ a } else iroot(a, mid, proc) } else { mid } } | x when x < 0 => { if (leftVal > 0){ if (mid - a == 1){ a } else iroot(a, mid, proc) } else if (leftVal < 0) { if (mid - a == 1){ a } else iroot(mid, b, proc) } else { mid } } | 0 => mid | _ => failwith("Incomplete Match Case error") }; }
let rec iroot: (int, int, int => int) => int = (a, b, proc) =>{ let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); switch (midVal){ | x when x > 0 => { if (leftVal > 0){ if (mid - a == 1){ a } else iroot(mid, b, proc) } else if (leftVal < 0) { if (mid - a == 1){ a } else iroot(a, mid, proc) } else { mid } } | x when x < 0 => { if (leftVal > 0){ if (mid - a == 1){ a } else iroot(a, mid, proc) } else if (leftVal < 0) { if (mid - a == 1){ a } else iroot(mid, b, proc) } else { mid } } | 0 => mid | _ => failwith("Incomplete Match Case error") }; }
let rec iroot: (int, int, int => int) => int = (a, b, proc) =>{ let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); let length = mid – a; switch (midVal){ | x when x > 0 => { if (leftVal > 0){ if (length == 1){ a } else iroot(mid, b, proc) } else if (leftVal < 0) { if (length == 1){ a } else iroot(a, mid, proc) } else { mid } }
| x when x < 0 => { if (leftVal > 0){ if (length == 1){ a } else iroot(a, mid, proc) } else if (leftVal < 0) { if (length == 1){ a } else iroot(mid, b, proc) } else { mid } } | 0 => mid | _ => failwith("Incomplete Match Case error") }; }
let rec iroot: (int, int, int => int) => int = (a, b, proc) =>{ let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); let short = (mid – a == 1); switch (midVal){ | x when x > 0 => { if (leftVal > 0){ if (short) { a } else iroot(mid, b, proc) } else if (leftVal < 0) { if (short) { a } else iroot(a, mid, proc) } else { mid } }
| x when x < 0 => { if (leftVal > 0){ if (short) { a } else iroot(a, mid, proc) } else if (leftVal < 0) { if (short) { a } else iroot(mid, b, proc) } else { mid } } | 0 => mid | _ => failwith("Incomplete Match Case error") }; }
let rec iroot: (int, int, int => int) => int = (a, b, proc) =>{ let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); let short = (mid – a == 1); switch (midVal){ | x when x > 0 => { if (leftVal > 0){ if (short) { a } else iroot(mid, b, proc) } else if (leftVal < 0) { if (short) { a } else iroot(a, mid, proc) } else { mid } }
| x when x < 0 => { if (leftVal > 0){ if (short) { a } else iroot(a, mid, proc) } else if (leftVal < 0) { if (short) { a } else iroot(mid, b, proc) } else { mid } } | 0 => mid | _ => failwith("Incomplete Match Case error") }; }
let rec iroot: (int, int, int => int) => int = (a, b, proc) =>{ let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); let short = (mid – a == 1); if (short) a else switch (midVal){ | x when x > 0 => { if (leftVal > 0){ iroot(mid, b, proc) } else if (leftVal < 0) { iroot(a, mid, proc) } else { mid } } | x when x < 0 => { if (leftVal > 0){ iroot(a, mid, proc) } else if (leftVal < 0) { iroot(mid, b, proc) } else { mid } } | 0 => mid | _ => failwith("Incomplete Match Case error") }; }
Now apparent there's an error: if mid = a + 1, we return a, whether the zero is between a and mid, or between mid and b! We'll leave this for now…
let rec iroot: (int, int, int => int) => int = (a, b, proc) =>{ let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); let short = (mid – a == 1); if (short) a else switch (midVal){ | x when x > 0 => { if (leftVal > 0){ iroot(mid, b, proc) } else if (leftVal < 0) { iroot(a, mid, proc) } else { mid } } | x when x < 0 => { if (leftVal > 0){ iroot(a, mid, proc) } else if (leftVal < 0) { iroot(mid, b, proc) } else { mid } } | 0 => mid | _ => failwith("Incomplete Match Case error") }; }
Let's clean up a little
let rec iroot: (int, int, int => int) => int = (a, b, proc) => { let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); let short = mid - a == 1; if (short) { a; } else { switch (midVal) { | x when x > 0 => if (leftVal > 0) { iroot(mid, b, proc); } else if (leftVal < 0) { iroot(a, mid, proc); } else { mid; }
| x when x < 0 => if (leftVal > 0) { iroot(a, mid, proc); } else if (leftVal < 0) { iroot(mid, b, proc); } else { mid; } | 0 => mid | _ => failwith("Incomplete Match Case error") }; }; };
We seem to be working with midVal and leftVal a lot. If either is zero…we know an answer!
let rec iroot: (int, int, int => int) => int = (a, b, proc) => { let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); let short = mid - a == 1; if (short) { a; } else { if (midVal == 0) {mid} else if (leftVal == 0) {a} else switch (midVal) { | x when x > 0 => if (leftVal > 0) { iroot(mid, b, proc); } else if (leftVal < 0) { iroot(a, mid, proc); } else { mid; }
| x when x < 0 => if (leftVal > 0) { iroot(a, mid, proc); } else if (leftVal < 0) { iroot(mid, b, proc); } else { mid; } | 0 => mid | _ => failwith("Incomplete Match Case error") }; }; };
Now we know they're both nonzero… but we keep testing midVal > 0 or leftVal > 0
let rec iroot: (int, int, int => int) => int = (a, b, proc) => { let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); let short = mid - a == 1; if (short) { a; } else { if (midVal == 0) {mid} else if (leftVal == 0) {a} else switch (midVal) { | x when x > 0 => if (leftVal > 0) { iroot(mid, b, proc); } else if (leftVal < 0) { iroot(a, mid, proc); } else { mid; }
| x when x < 0 => if (leftVal > 0) { iroot(a, mid, proc); } else if (leftVal < 0) { iroot(mid, b, proc); } else { mid; } | 0 => mid | _ => failwith("Incomplete Match Case error") }; }; };
That last case can go away…and if we switch on "midVal > 0", things simplify!
let rec iroot: (int, int, int => int) => int = (a, b, proc) => { let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); let short = mid - a == 1; if (short) { a; } else { if (midVal == 0) {mid} else if (leftVal == 0) {a} else switch (midVal > 0) { | true => if (leftVal > 0) { iroot(mid, b, proc); } else if (leftVal < 0) { iroot(a, mid, proc); } else { mid; }
| false => if (leftVal > 0) { iroot(a, mid, proc); } else if (leftVal < 0) { iroot(mid, b, proc); } else { mid; } }; }; };
That last case can go away…and if we switch on "midVal > 0", things simplify!
let rec iroot: (int, int, int => int) => int = (a, b, proc) => { let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); let short = mid - a == 1; if (short) { a; } else { if (midVal == 0) {mid} else if (leftVal == 0) {a} else switch (midVal > 0) { | true => if (leftVal > 0) { iroot(mid, b, proc); } else if (leftVal < 0) { iroot(a, mid, proc); } else { mid; } | false => if (leftVal > 0) { iroot(a, mid, proc); } else if (leftVal < 0) { iroot(mid, b, proc); } else { mid; } }; }; };
The fjnal case (in purple) for each clause can go away…
let rec iroot: (int, int, int => int) => int = (a, b, proc) => { let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); let short = mid - a == 1; if (short) { a; } else { if (midVal == 0) {mid} else if (leftVal == 0) {a} else switch (midVal > 0) { | true => if (leftVal > 0) { iroot(mid, b, proc); } else if (leftVal < 0) { iroot(a, mid, proc); }
| false => if (leftVal > 0) { iroot(a, mid, proc); } else if (leftVal < 0) { iroot(mid, b, proc); } }; }; };
The else-ifs become "else" because if it's not positive, it's negative….
let rec iroot: (int, int, int => int) => int = (a, b, proc) => { let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); let short = mid - a == 1; if (short) { a; } else { if (midVal == 0) {mid} else if (leftVal == 0) {a} else switch (midVal > 0) { | true => if (leftVal > 0) { iroot(mid, b, proc); } else { iroot(a, mid, proc); }
| false => if (leftVal > 0) { iroot(a, mid, proc); } else { iroot(mid, b, proc); } }; }; };
The else-ifs become "else" because if it's not positive, it's negative….
let rec iroot: (int, int, int => int) => int = (a, b, proc) => { let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); let short = mid - a == 1; if (short) { a; } else { if (midVal == 0) {mid} else if (leftVal == 0) {a} else switch (midVal > 0) { | true => if (leftVal > 0) { iroot(mid, b, proc); } else { iroot(a, mid, proc); }
| false => if (leftVal > 0) { iroot(a, mid, proc); } else { iroot(mid, b, proc); } }; }; };
Switching on a boolean is weird…normally we'd replace with "if"… but there's leftVal > 0 too!
let rec iroot: (int, int, int => int) => int = (a, b, proc) => { let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); let short = mid - a == 1; if (short) { a; } else { if (midVal == 0) {mid} else if (leftVal == 0) {a} else switch (midVal > 0, leftVal > 0) { | (true, true) => iroot(mid, b, proc); | (true, false)=> iroot(a, mid, proc); | (false, true) => iroot(a, mid, proc); | (false, false) => iroot(mid, b, proc); }; }; };
Neaten up indentation again…
let rec iroot: (int, int, int => int) => int = (a, b, proc) => { let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); let short = mid - a == 1; if (short) { a; } else if (midVal == 0) { mid; } else if (leftVal == 0) { a; } else { switch (midVal > 0, leftVal > 0) { | (true, true) => iroot(mid, b, proc) | (true, false) => iroot(a, mid, proc) | (false, true) => iroot(a, mid, proc) | (false, false) => iroot(mid, b, proc) }; }; };
The right-hand side of middle two cases seem the same; right-hand side of outer two cases seem the same…
let rec iroot: (int, int, int => int) => int = (a, b, proc) => { let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); let short = mid - a == 1; if (short) { a; } else if (midVal == 0) { mid; } else if (leftVal == 0) { a; } else { switch (midVal > 0, leftVal > 0) { | (true, true) => iroot(mid, b, proc) | (false, false) => iroot(mid, b, proc) | (true, false) => iroot(a, mid, proc) | (false, true) => iroot(a, mid, proc) }; }; };
In fjrst pair, booleans are same; in second, they difger
let rec iroot: (int, int, int => int) => int = (a, b, proc) => { let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); let short = (mid - a == 1); if (short) { a; } else if (midVal == 0) { mid; } else if (leftVal == 0) { a; } else { switch ((midVal > 0) == (leftVal > 0)) { | true => iroot(mid, b, proc) | false => iroot(a, mid, proc) }; }; };
We defjne "short", then use it just once…
let rec iroot: (int, int, int => int) => int = (a, b, proc) => { let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); if (mid - a == 1) { a; } else if (midVal == 0) { mid; } else if (leftVal == 0) { a; } else { switch ((midVal > 0) == (leftVal > 0)) { | true => iroot(mid, b, proc) | false => iroot(a, mid, proc) }; }; };
We defjne "short", then use it just once…
let rec iroot: (int, int, int => int) => int = (a, b, proc) => { let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); if (mid - a == 1) { a; } else if (midVal == 0) { mid; } else if (leftVal == 0) { a; } else { switch ((midVal > 0) == (leftVal > 0)) { | true => iroot(mid, b, proc) | false => iroot(a, mid, proc) }; }; };
Now we can look at making the code right! Obs 1: if b – a > 1, then mid is difgerent from both b and a Obs 2: if b – a = 1, then the interval [a, a+1] contains a zero Obs 3: no harm in recurring all the way to an interval of length one. (Log cost)
let rec iroot: (int, int, int => int) => int = (a, b, proc) => { if (b == a + 1) {a} else { let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); if (mid - a == 1) { a; } else if (midVal == 0) { mid; } else if (leftVal == 0) { a; } else { switch ((midVal > 0) == (leftVal > 0)) { | true => iroot(mid, b, proc) | false => iroot(a, mid, proc) }; }; }; };
Now we can look at making the code right! Obs 1: if b – a > 1, then mid is difgerent from both b and a Obs 2: if b – a = 1, then the interval [a, a+1] contains a zero Obs 3: no harm in recurring all the way to an interval of length one (Log cost)
let rec iroot: (int, int, int => int) => int = (a, b, proc) => { if (b == a + 1) {a} else { let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); if (mid - a == 1) { a; } else if (midVal == 0) { mid; } else if (leftVal == 0) { a; } else { switch ((midVal > 0) == (leftVal > 0)) { | true => iroot(mid, b, proc) | false => iroot(a, mid, proc) }; }; }; };
Now we can look at making the code right! Obs 1: if b – a > 1, then mid is difgerent from both b and a Obs 2: if b – a = 1, then the interval [a, a+1] contains a zero Obs 3: no harm in recurring all the way to an interval of length one (Log cost)
let rec iroot: (int, int, int => int) => int = (a, b, proc) => { if (b == a + 1) {a} else { let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); if (midVal == 0) { mid; } else if (leftVal == 0) { a; } else { switch ((midVal > 0) == (leftVal > 0)) { | true => iroot(mid, b, proc) | false => iroot(a, mid, proc) }; }; }; };
Now we can look at making the code right! Obs 1: if b – a > 1, then mid is difgerent from both b and a Obs 2: if b – a = 1, then the interval [a, a+1] contains a zero Obs 3: no harm in recurring all the way to an interval of length one (Log cost)
let rec iroot: (int, int, int => int) => int = (a, b, proc) => { if (b == a + 1) {a} else { let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); switch ((midVal > 0) == (leftVal > 0)) { | true => iroot(mid, b, proc) | false => iroot(a, mid, proc) }; }; };
Now we can look at making the code right! Obs 1: if b – a > 1, then mid is difgerent from both b and a Obs 2: if b – a = 1, then the interval [a, a+1] contains a zero Obs 3: no harm in recurring all the way to an interval of length one (Log cost)
let rec iroot: (int, int, int => int) => int = (a, b, proc) => { if (b == a + 1) {a} else { let mid = (a + b) / 2; let midVal = proc(mid); let leftVal = proc(a); switch ((midVal > 0) == (leftVal > 0)) { | true => iroot(mid, b, proc) | false => iroot(a, mid, proc) }; }; };
midVal and leftVal defjned, then used only once
let rec iroot: (int, int, int => int) => int = (a, b, proc) => { if (b == a + 1) {a} else { let mid = (a + b) / 2; switch ((proc(mid) > 0) == (proc(a) > 0)) { | true => iroot(mid, b, proc) | false => iroot(a, mid, proc) }; }; };
midVal and leftVal defjned, then used only once
let rec iroot: (int, int, int => int) => int = (a, b, proc) => { if (b == a + 1) {a} else { let mid = (a + b) / 2; switch ((proc(mid) > 0) == (proc(a) > 0)) { | true => iroot(mid, b, proc) | false => iroot(a, mid, proc) }; }; };
switching on T/F is weird
let rec iroot: (int, int, int => int) => int = (a, b, proc) => { if (b == a + 1) {a} else { let mid = (a + b) / 2; if ((proc(mid) > 0) == (proc(a) > 0)) { iroot(mid, b, proc) } else { iroot(a, mid, proc)}; }; };
switching on T/F is weird Also: reorder tests to go left-to-right
let rec iroot: (int, int, int => int) => int = (a, b, proc) => if (b == a + 1) {a} else { let mid = (a + b) / 2; if ((proc(a) > 0) == (proc(mid) > 0)) { iroot(mid, b, proc) } else { iroot(a, mid, proc) }; };
We're now using the fact that if proc has difgerent "signs" (positive, negative, OR zero) at the two ends of the interv then there's a root in the interval. Need to add this to the spec for proc!
/* input: a, lower endpoint of an interval b, upper endpoint of an interval, b > a. proc, an int->int function whose signs (positive, zero, negative) at a and b differ
a number n between a and b-1, inclusive, with proc(n) and proc(n+1) having differing signs, so that the interval [n, n+1] contains a zero of proc. */ let rec iroot: (int, int, int => int) => int = (a, b, proc) => if (b == a + 1) {a} else { let mid = (a + b) / 2; if ((proc(a) > 0) == (proc(mid) > 0)) { iroot(mid, b, proc) } else { iroot(a, mid, proc) }; };
let rec iroot: (int, int, int => int) => int = (n, m, proc) =>{ let newBound = (n+m)/2; let procApply = proc(newBound); let procApplyN = proc(n); switch(procApply){ |x when x > 0 => { if(procApplyN > 0){ if(newBound-n == 1){ n } else iroot(newBound, m, proc) } else if (procApplyN < 0) { if(newBound-n == 1){ n } else iroot(n, newBound, proc) } else { newBound } }
|x when x < 0 => { if(procApplyN > 0){ if(newBound-n == 1){ n } else iroot(n, newBound, proc) } else if (procApplyN < 0) { if(newBound-n == 1){ n } else iroot(newBound, m, proc) } else { newBound } } |0 => newBound | _ => failwith("Incomplete Match Case error") }; }