(* reviewing map and filter *) fun testEven([]) = [] | testEven(x::rest) = (x mod 2 = 0) :: testEven(rest); fun scale(f, []) = [] | scale(f, x::rest) = x * f :: scale(f, rest); fun makeReals([]) = [] | makeReals(x::rest) = real(x)::makeReals(rest); fun listify([]) = [] | listify(x::rest) = [x]::listify(rest); fun switchPairs([]) = [] | switchPairs((a,b)::rest) = (b,a) :: switchPairs(rest); fun sumPairs([]) = [] | sumPairs((a,b)::rest) = (a + b) :: sumPairs(rest); fun map(f, []) = [] | map(f, a::rest) = f(a)::map(f, rest); fun testEven(xx) = map(fn (x) => x mod 2 = 0, xx); fun scale(f, xx) = map (fn (x) => f * x, xx); fun makeReals(xx) = map(real, xx); fun listify(xx) = map(fn(x) => [x], xx); fun switchPairs(xx) = map(fn(a,b) => (b,a), xx); fun keepEvens([]) = [] | keepEvens(a::rest) = if a mod 2 = 0 then a::keepEvens(rest) else keepEvens(rest); fun contains(x, []) = false | contains(x, y::rest) = x = y orelse contains(x, rest); fun intersection([], bb) = [] | intersection(a::rest, bb) = if contains(a, bb) then a::intersection(rest, bb) else intersection(rest, bb); fun filter(f, []) = [] | filter(f, a::rest) = if f(a) then a::filter(f, rest) else filter(f, rest); fun keepEvens(xx) = filter(fn(x) => x mod 2 = 0, xx); fun intersection(aa, bb) = filter(fn(x) => contains(x, bb), aa); (* examples from earlier *) fun sum([]) = 0 | sum(x::rest) = x + sum(rest); fun product([]) = 1 | product(x::rest) = x * product(rest); fun count([]) = 0 | count(x::rest) = 1 + count(rest); fun reverse([]) = [] | reverse(x::rest) = reverse(rest) @ [x]; fun contains(y, []) = false | contains(y, x::rest) = if x = y then true else contains(y, rest); (* foldr *) fun foldr(f, s, []) = s | foldr(f, s, x::rest) = f(x, foldr(f, s, rest)); (* rewriting earlier examples using foldr *) fun sum(xx) = foldr(fn(x, y) => x + y, 0, xx); fun prod(xx) = foldr(fn(x, y) => x * y, 1, xx); fun count(xx) = foldr(fn(x,y) => 1 + y, 0, xx); fun reverse(xx) = foldr(fn(x,y) => y @ [x], [], xx); fun contains(a, xx) = foldr(fn(x,y) => (a = x) orelse y, false, xx); (* foldl *) fun foldl(f, s, []) = s | foldl(f, s, x::rest) = foldl(f, f(x, s), rest); (* "Function" example (from precalc/calculus) *) val p = [6.0, 2.0, 0.0, 12.0, 8.0] fun pow(x, 0) = 1.0 | pow(x, n) = x * pow(x, n-1); (* Brutest of brute force *) fun evaluatePoly([], x) = 0.0 | evaluatePoly(c::rest, x) = c * pow(x, count(rest)) + evaluatePoly(rest, x); (* We could almost do this using foldr, but we would have no way of knowing the exponent of x (that is, the result of count(rest). *) fun evaluatePoly(coeffs, x) = foldr(fn (c, y) => c * pow(x, ???) + y, 0.0, coeffs); (* More efficient brute force, though much harder to program and understand *) fun evaluatePoly(coeffs, x) = (* evalPolyHelper returns a tuple containing the the value of resulting the sub-polynomial and the current power of x *) let fun evalPolyHelper([]) = (0.0, 1.0) | evalPolyHelper(c::rest) = let val (v, p) = evalPolyHelper(rest) in (c*p + v, x * p) end; in #1(evalPolyHelper(coeffs)) end; fun evaluatePoly(coeffs, x) = foldl(fn(c, y) => c + y * x, 0.0, coeffs); (* For 7.14.c (7.B) *) fun evaluatePoly(coeffs, x) = #1(foldr(fn(c, (y, px)) => ( ??, ??), (??, ??), coeffs)); fun differentiatePoly([]) = ([], 0) | differentiatePoly([c]) = ([], 1) | differentiatePoly(c::rest) = let val (diffRest, degree) = differentiatePoly(rest) in (real(degree) * c ::diffRest, degree + 1) end; fun differentiatePoly(coeffs) = #1(foldr(fn(c, (derivCoeffs, degree)) => (if degree = 0 then [] else real(degree) * c::derivCoeffs, degree + 1), ([], 0), coeffs)); fun indefIntegratePoly(coeffs) = #1(foldr(fn(c, (integCoeffs, degree)) => ((c / real(degree))::integCoeffs, degree + 1), ([0.0], 1), coeffs)); fun defIntegratePoly(coeffs, min, max) = let val indefIntegral = indefIntegratePoly(coeffs) in evaluatePoly(indefIntegral, max) - evaluatePoly(indefIntegral, min) end; datatype function = Poly of real list | Exp of real | Step of real * real; fun evaluate(Poly(coeffs), x) = foldl(fn(c, y) => c + y * x, 0.0, coeffs) | evaluate(Exp(c), x) = c * Real.Math.exp(x) | evaluate(Step(v, c), x) = if x < v then 0.0 else c; datatype function = Func of (real -> real) * (unit -> function) * (real * real -> real); fun makePolynomial(coeffs) = Func ((* Evaluate *) fn (x) => foldr(fn(c, y) => c + y * x, 0.0, coeffs), (* Find derivative *) fn () => makePolynomial(#1(foldr(fn(c, (derivCoeffs, degree)) => (if degree = 0 then [] else real(degree) * c::derivCoeffs, degree + 1), ([], 0), coeffs))), (* Compute definite integral *) fn (min, max) => let val Func(evaluateIntegral, _, _) = makePolynomial(#1(foldl(fn(c, (integCoeffs, degree)) => ((c / real(degree))::integCoeffs, degree + 1), ([0.0], 1), coeffs))); in evaluateIntegral(max) - evaluateIntegral(min) end); fun makeStep(stepPoint, stepLevel) = Func (fn (x) => if x < stepPoint then 0.0 else stepLevel, fn () => makePolynomial([0.0]), fn (min, max) => let val (rmin, rmax, sign) = if min <= max then (min, max, 1.0) else (max, min, ~1.0) in sign * (if max < stepPoint then 0.0 else if min > stepPoint then stepLevel * (max - min) else stepLevel * (max - stepPoint)) end); fun makeExponential(coefficient) = Func (fn (x) => coefficient * Real.Math.exp(x), fn () => makeExponential(coefficient), fn (min, max) => coefficient * (Real.Math.exp(max) - Real.Math.exp(min)));