get polynom representation for lagrangian interpolation - f#

How can I represent an incomplete mathematical function?
I need to do something like (x - constant) then
(x - constant)*(x - another) => (x^2 - x * constant - x * another + constant * another)
and so on.
I'm trying to make a program to do Lagrangian interpolation (finding a function for some points)
so I need to make a function that I can see (print, or something), from a set of known values.
sorry if confusing.

In case you want to implement the Lagrange Interpolation as discussed here
getting a function that interpolates values:
then this is the direct translation into F#:
let LagrangeInterpol (points : (Double*Double)[]) x =
let indizes = [0..points.Length-1]
let p j =
indizes
|> List.map (fun k ->
if k <> j
then (x - fst points.[k])
/ (fst points.[j] - fst points.[k])
else 1.0)
|> List.fold (*) 1.0
indizes |> List.sumBy (fun j -> p j * snd points.[j])
examples
Here is a simple test-session:
> let points = [|0.0,0.0; 1.0,2.0; 2.0,3.0|];;
val points : (float * float) [] = [|(0.0, 0.0); (1.0, 2.0); (2.0, 3.0)|]
> let f = LagrangeInterpol points;;
val f : (Double -> float)
> f 0.0;;
val it : float = 0.0
> f 1.0;;
val it : float = 2.0
> f 2.0;;
val it : float = 3.0
So I hope I did not make any major mistake.
Please note that I made no efford to do any performance optimizations here - this should be sufficent to draw a graph or get a few values in between.
getting a representation of the polynom
This is a bit more trickier - you can either try to come up with the combinatorical formulas for the coefficients or (like me here) be mathematical lazy and just implement a Polynom-Type with just enough operators:
type Polynom =
Poly of float list with
override p.ToString () =
match p with
| Poly coefs ->
System.String.Join (" + ", coefs |> List.mapi (fun i c -> sprintf "%AX^%d" c i))
static member Const c = Poly [c]
static member Zero = Polynom.Const 0.0
static member One = Polynom.Const 1.0
static member X = Poly [0.0; 1.0]
static member (+) (Poly cs1, Poly cs2) =
let m = max (List.length cs1) (List.length cs2)
List.zip (ofLen m cs1) (ofLen m cs2)
|> List.map (fun (a,b) -> a+b)
|> Poly
static member (-) (Poly cs1, Poly cs2) =
let m = max (List.length cs1) (List.length cs2)
List.zip (ofLen m cs1) (ofLen m cs2)
|> List.map (fun (a,b) -> a-b)
|> Poly
static member (*) (f : float, Poly cs2) : Polynom =
cs2
|> List.map (fun c -> f * c)
|> Poly
static member private shift n (Poly cs) =
List.replicate n 0.0 # cs |> Poly
static member (*) (Poly cs1, p2 : Polynom) : Polynom =
cs1
|> List.mapi (fun i c -> Polynom.shift i (c * p2))
|> List.sum
static member (/) (Poly cs1, f : float) : Polynom =
cs1
|> List.map (fun c -> c / f)
|> Poly
Here I just use a list of floats to represent the coefficients of a polynom (so X^2 + 2X + 3 is Poly [3.0; 2.0; 1.0] note that the ith coefficient is the one at X^i.
Having this we can use almost the same function as before:
let getPolynom (points : (float * float)[]) =
let indizes = [0..points.Length-1]
let p j =
indizes
|> List.map (fun k ->
if k <> j
then (Polynom.X - Polynom.Const (fst points.[k]))
/ (fst points.[j] - fst points.[k])
else Polynom.One)
|> List.fold (*) Polynom.One
indizes |> List.sumBy (fun j -> Polynom.Const (snd points.[j]) * p j)
As you can see I used the same function and only replaces the argument x with Polynom.X and wrapped the constants approbiatley.
examples
and here are two examples (compare them to the Wiki-Page they should be right):
> LagrangeInterpolation.getPolynom
[|(1.0, 1.0); (2.0, 4.0); (3.0, 9.0)|] |> string;;
val it : string = "0.0X^0 + 0.0X^1 + 1.0X^2"
> LagrangeInterpolation.getPolynom
[| 1.0,1.0; 2.0,8.0; 3.0,27.0 |] |> string;;
val it : string = "6.0X^0 + -11.0X^1 + 6.0X^2"
complete code with helpers
the complete code for this inside a module is:
module LagrangeInterpolation =
let private ofLen n cs =
let l = List.length cs
if l < n
then cs # List.replicate (n-l) 0.0
else cs
type Polynom =
Poly of float list with
override p.ToString () =
match p with
| Poly coefs ->
System.String.Join (" + ", coefs |> List.mapi (fun i c -> sprintf "%AX^%d" c i))
static member Const c = Poly [c]
static member Zero = Polynom.Const 0.0
static member One = Polynom.Const 1.0
static member X = Poly [0.0; 1.0]
static member (+) (Poly cs1, Poly cs2) =
let m = max (List.length cs1) (List.length cs2)
List.zip (ofLen m cs1) (ofLen m cs2)
|> List.map (fun (a,b) -> a+b)
|> Poly
static member (-) (Poly cs1, Poly cs2) =
let m = max (List.length cs1) (List.length cs2)
List.zip (ofLen m cs1) (ofLen m cs2)
|> List.map (fun (a,b) -> a-b)
|> Poly
static member (*) (f : float, Poly cs2) : Polynom =
cs2
|> List.map (fun c -> f * c)
|> Poly
static member private shift n (Poly cs) =
List.replicate n 0.0 # cs |> Poly
static member (*) (Poly cs1, p2 : Polynom) : Polynom =
cs1
|> List.mapi (fun i c -> Polynom.shift i (c * p2))
|> List.sum
static member (/) (Poly cs1, f : float) : Polynom =
cs1
|> List.map (fun c -> c / f)
|> Poly
let getPolynom (points : (float * float)[]) =
let indizes = [0..points.Length-1]
let p j =
indizes
|> List.map (fun k ->
if k <> j
then (Polynom.X - Polynom.Const (fst points.[k]))
/ (fst points.[j] - fst points.[k])
else Polynom.One)
|> List.fold (*) Polynom.One
indizes |> List.sumBy (fun j -> Polynom.Const (snd points.[j]) * p j)
remarks
For better output you should probably add some simplifications (for example Poly [1.0;0.0] -> Poly [1.0]) and improve the ToString method but I'm sure you can handle ;)

If you mean a function that is partial, i.e. it is undefined on some of its inputs, then there are generally two ways to deal with this. One option is to use option<'T> type and wrap the correct result in Some or return None when the value is undefined. For example:
let safeDivide a b =
if b = 0 then None else Some(a / b)
The caller than has to pattern match on the result (or use something like the Maybe computation builder) which makes calling the function harder, but you have full control over how the error is handled.
The other option is to throw an exception. This happens automatically for integer division, but you could write something like this:
let safeDivide a b =
if b = 0 then invalidArg "b" "Division by zero!"
a / b
This is a bit easier to write, but you need to be aware of the behavior and handle the exceptions correctly.

Related

How to allow a function to accept a generic list of functions?

How to allow a function to accept a generic list of functions?
I have the code below, but the compiler is rejecting the line where I try to set partiallyAppliedAdds, with the error:
Type mismatch. Expecting a int -> int' given a int -> 'a -> 'b'
type ApplicativeFunctor(fnList: 'a list) =
member private this.fnList: 'a list = fnList
member this.ap (apTarget: int list) = ([], this.fnList) ||> List.fold (fun (acc: 'a list) fn -> acc # (apTarget |> List.map fn))
let add1 a = a + 1
ApplicativeFunctor([add1]).ap([1]) // [2]
let arg1 = [1; 3]
let add x = fun y -> x + y
let partiallyAppliedAdds = ApplicativeFunctor[add].ap(arg1) // Type mismatch. Expecting a int -> int' given a int -> 'a -> 'b'
Is this easily accomplishable in F#, or should I approach this differently?
To fix your version, you do:
type ApplicativeFunctor<'a,'b>(fnList: list<'a -> 'b>) =
member private _.fnList = fnList
member this.ap apTarget =
([], this.fnList)
||> List.fold (fun acc fn -> acc # List.map fn apTarget)
let add1 a = a + 1
let res1 = ApplicativeFunctor([add1]).ap([1]) (* [2] *)
printfn "%A" res1
let paAdd = ApplicativeFunctor[fun x y -> x + y].ap([1;3])
printfn "%A" paAdd
But the general approach is just
let ap fs xs =
List.foldBack2 (fun f x state ->
f x :: state
) fs xs []
let add x y z = x + y + z
let xs = [1..3]
let ys = [10;20;30]
let zs = [100;200;300]
let res1 = (ap (ap (List.map add xs) ys) zs)
printfn "%A" res1 (* [111;222;333] *)
(* Custom operators *)
let (<!>) = List.map
let (<*>) = ap
let res2 = add <!> xs <*> ys <*> zs
printfn "%A" res2 (* [111;222;333] *)

How does one specify a list type in a function parameter?

I have a function that takes two lists and generates a Cartesian product.
let cartesian xs ys = xs |> List.collect (fun x -> ys |> List.map (fun y -> x * y))
My problem is I am passing two lists of type Int64, and I am getting errors because the function is expecting two lists of type Int32.
How does one explicitly set the list type?
Adding a type annotation to one of the arguments should work:
let cartesian (xs: int64 list) ys =
xs |> List.collect (fun x -> ys |> List.map (fun y -> x * y))
Alternatively, use inline to infer types at call site:
let inline cartesian xs ys =
xs |> List.collect (fun x -> ys |> List.map (fun y -> x * y))
> cartesian [1;2;3] [1;2;3];;
val it : int list = [1; 2; 3; 2; 4; 6; 3; 6; 9]
> cartesian [1L;2L;3L] [1L;2L;3L];;
val it : int64 list = [1L; 2L; 3L; 2L; 4L; 6L; 3L; 6L; 9L]
Extended comment: A third alternative exists, factoring out the part of the code which introduces the constraint. Because the F# multiplication operator has the signature
val inline ( * ) : ^T1 -> ^T2 -> ^T3
when (^T1 or ^T2) : (static member (*) : ^T1 * ^T2 -> ^T3)
its static member constraint cannot be generalized unless the code in which it appears is marked inline. Move the operator to the call site:
let cartesian f xs ys =
List.collect (fun x -> List.map (f x) ys) xs
// val cartesian : f:('a -> 'b -> 'c) -> xs:'a list -> ys:'b list -> 'c list
cartesian (*) [1L..3L] [1L..3L]
// val it : int64 list = [1L; 2L; 3L; 2L; 4L; 6L; 3L; 6L; 9L]

F# Polynomial Derivator

I'm writing a program that takes a polynomial and returns its derivative. The polynomial is passed as predefined type "poly", which is a list of tuples in which the first element is a float representing a coefficient, and the second is an integer representing the degree of that term. So a poly p = [(2.0, 3);(1.5,2);(3.2;1)] would represent 2x^3 + 1.5x^2 + 3.2x^1. My code is as follows:
let rec diff (p:poly):poly =
match p with
| [] -> raise EmptyList
| [a]-> (fst a * snd a, snd a - 1)
| x::xs -> ((fst x * snd x), (snd x - 1)) :: diff xs
The error I'm getting tells me that the program expects the function to return a type poly, but here has the type 'a * 'b. I don't see why thats the case, when in my base case I return a tuple and in all other situations I'm appending onto an accumulating list. I've played around with the brackets, to no avail. Why is my code tossing this error?
All input is appreciated on the matter.
you said it yourself: in the base case you are returning a tuple not a list - so the inference thinks this is what you want
Just change it into:
let rec diff (p:poly):poly =
match p with
| [] -> raise EmptyList
| [a]-> [fst a * snd a, snd a - 1]
| x::xs -> ((fst x * snd x), (snd x - 1)) :: diff xs
and it should be fine (just replace the (..) with [..] ;) )
remember: :: will cons a new head onto a list
there are a few issues with float vs. int there so I would suggest this (using recursion):
type Poly = (float*int) list
let test : Poly = [(2.0, 3);(1.5,2);(3.2,1);(1.0,0)]
let rec diff (p:Poly):Poly =
match p with
| [] -> []
| x::xs -> (fst x * float (snd x), snd x - 1) :: diff xs
which is really just this:
let diff : Poly -> Poly =
List.map (fun x -> fst x * float (snd x), snd x - 1)
and can look a lot nicer without fst and snd:
let diff : Poly -> Poly =
List.map (fun (a,p) -> a * float p, p - 1)

How do you sum up and average a Sequence?

Say I have a coordinate (x, y) and its neighbors in a sequences of sequence (-1, 1)(0, 1)(1, 1)(-1, 0)(0, 0)(1, 0)(-1, -1)(0, -1)(1, -1)
let n = [1 .. -1 .. -1]
|> Seq.collect (fun j -> [-1 .. 1] |> Seq.map(fun i -> [i, j]))
n |> Seq.iter(printf "%A")
I'm trying to add x and y to each element in the sequence respectively
Then get Color p = GetPixel(x+i, y+j) for every element in sequence, sum up and average out their R, G, B for (x,y)
So we have 9 Red, 9 Green, 9 Blue to Ave(Red), Ave(Blue), Ave(Green)
let offsets = seq { for i in -1 .. 1 do for j in -1 .. 1 do yield (i, j) }
let neighbourhood (x, y) = Seq.map (fun (i, j) -> (x + i, y + j)) offsets
let avgColours (cs : System.Drawing.Color seq) =
let ((r, g, b), c) = cs |> Seq.fold (fun ((r, g, b), c) col -> ((r + int col.R, g + int col.G, b + int col.B), c + 1)) ((0, 0, 0), 0)
System.Drawing.Color.FromArgb(r / c, g / c, b / c)
let avgNeighbours p = p |> neighbourhood |> Seq.map (fun (x, y) -> GetPixel(x, y)) |> avgColours
Something like this?
let f x y =
let n = [1 .. -1 .. -1] |> Seq.collect (fun j -> [-1 .. 1] |> Seq.map(fun i -> (i, j)))
n |> Seq.map (fun (i,j) -> x+i,y+j)
|> Seq.map bitmapobject.GetPixel
|> Seq.map (fun c -> float c.R, float c.G, float c.B)
|> Seq.fold (fun (R,G,B) (r,g,b) -> (R+r, G+g, B+b)) (0.0, 0.0, 0.0)
|> (fun (r,g,b) -> (r/9.0, g/9.0, b/9.0))

Combine memoization and tail-recursion

Is it possible to combine memoization and tail-recursion somehow? I'm learning F# at the moment and understand both concepts but can't seem to combine them.
Suppose I have the following memoize function (from Real-World Functional Programming):
let memoize f = let cache = new Dictionary<_, _>()
(fun x -> match cache.TryGetValue(x) with
| true, y -> y
| _ -> let v = f(x)
cache.Add(x, v)
v)
and the following factorial function:
let rec factorial(x) = if (x = 0) then 1 else x * factorial(x - 1)
Memoizing factorial isn't too difficult and making it tail-recursive isn't either:
let rec memoizedFactorial =
memoize (fun x -> if (x = 0) then 1 else x * memoizedFactorial(x - 1))
let tailRecursiveFactorial(x) =
let rec factorialUtil(x, res) = if (x = 0)
then res
else let newRes = x * res
factorialUtil(x - 1, newRes)
factorialUtil(x, 1)
But can you combine memoization and tail-recursion? I made some attempts but can't seem to get it working. Or is this simply not possible?
As always, continuations yield an elegant tailcall solution:
open System.Collections.Generic
let cache = Dictionary<_,_>() // TODO move inside
let memoizedTRFactorial =
let rec fac n k = // must make tailcalls to k
match cache.TryGetValue(n) with
| true, r -> k r
| _ ->
if n=0 then
k 1
else
fac (n-1) (fun r1 ->
printfn "multiplying by %d" n //***
let r = r1 * n
cache.Add(n,r)
k r)
fun n -> fac n id
printfn "---"
let r = memoizedTRFactorial 4
printfn "%d" r
for KeyValue(k,v) in cache do
printfn "%d: %d" k v
printfn "---"
let r2 = memoizedTRFactorial 5
printfn "%d" r2
printfn "---"
// comment out *** line, then run this
//let r3 = memoizedTRFactorial 100000
//printfn "%d" r3
There are two kinds of tests. First, this demos that calling F(4) caches F(4), F(3), F(2), F(1) as you would like.
Then, comment out the *** printf and uncomment the final test (and compile in Release mode) to show that it does not StackOverflow (it uses tailcalls correctly).
Perhaps I'll generalize out 'memoize' and demonstrate it on 'fib' next...
EDIT
Ok, here's the next step, I think, decoupling memoization from factorial:
open System.Collections.Generic
let cache = Dictionary<_,_>() // TODO move inside
let memoize fGuts n =
let rec newFunc n k = // must make tailcalls to k
match cache.TryGetValue(n) with
| true, r -> k r
| _ ->
fGuts n (fun r ->
cache.Add(n,r)
k r) newFunc
newFunc n id
let TRFactorialGuts n k memoGuts =
if n=0 then
k 1
else
memoGuts (n-1) (fun r1 ->
printfn "multiplying by %d" n //***
let r = r1 * n
k r)
let memoizedTRFactorial = memoize TRFactorialGuts
printfn "---"
let r = memoizedTRFactorial 4
printfn "%d" r
for KeyValue(k,v) in cache do
printfn "%d: %d" k v
printfn "---"
let r2 = memoizedTRFactorial 5
printfn "%d" r2
printfn "---"
// comment out *** line, then run this
//let r3 = memoizedTRFactorial 100000
//printfn "%d" r3
EDIT
Ok, here's a fully generalized version that seems to work.
open System.Collections.Generic
let memoize fGuts =
let cache = Dictionary<_,_>()
let rec newFunc n k = // must make tailcalls to k
match cache.TryGetValue(n) with
| true, r -> k r
| _ ->
fGuts n (fun r ->
cache.Add(n,r)
k r) newFunc
cache, (fun n -> newFunc n id)
let TRFactorialGuts n k memoGuts =
if n=0 then
k 1
else
memoGuts (n-1) (fun r1 ->
printfn "multiplying by %d" n //***
let r = r1 * n
k r)
let facCache,memoizedTRFactorial = memoize TRFactorialGuts
printfn "---"
let r = memoizedTRFactorial 4
printfn "%d" r
for KeyValue(k,v) in facCache do
printfn "%d: %d" k v
printfn "---"
let r2 = memoizedTRFactorial 5
printfn "%d" r2
printfn "---"
// comment out *** line, then run this
//let r3 = memoizedTRFactorial 100000
//printfn "%d" r3
let TRFibGuts n k memoGuts =
if n=0 || n=1 then
k 1
else
memoGuts (n-1) (fun r1 ->
memoGuts (n-2) (fun r2 ->
printfn "adding %d+%d" r1 r2 //%%%
let r = r1+r2
k r))
let fibCache, memoizedTRFib = memoize TRFibGuts
printfn "---"
let r5 = memoizedTRFib 4
printfn "%d" r5
for KeyValue(k,v) in fibCache do
printfn "%d: %d" k v
printfn "---"
let r6 = memoizedTRFib 5
printfn "%d" r6
printfn "---"
// comment out %%% line, then run this
//let r7 = memoizedTRFib 100000
//printfn "%d" r7
The predicament of memoizing tail-recursive functions is, of course, that when tail-recursive function
let f x =
......
f x1
calls itself, it is not allowed to do anything with a result of the recursive call, including putting it into cache. Tricky; so what can we do?
The critical insight here is that since the recursive function is not allowed to do anything with a result of recursive call, the result for all arguments to recursive calls will be the same! Therefore if recursion call trace is this
f x0 -> f x1 -> f x2 -> f x3 -> ... -> f xN -> res
then for all x in x0,x1,...,xN the result of f x will be the same, namely res. So the last invocation of a recursive function, the non-recursive call, knows the results for all the previous values - it is in a position to cache them. The only thing you need to do is to pass a list of visited values to it. Here is what it might look for factorial:
let cache = Dictionary<_,_>()
let rec fact0 l ((n,res) as arg) =
let commitToCache r =
l |> List.iter (fun a -> cache.Add(a,r))
match cache.TryGetValue(arg) with
| true, cachedResult -> commitToCache cachedResult; cachedResult
| false, _ ->
if n = 1 then
commitToCache res
cache.Add(arg, res)
res
else
fact0 (arg::l) (n-1, n*res)
let fact n = fact0 [] (n,1)
But wait! Look - l parameter of fact0 contains all the arguments to recursive calls to fact0 - just like the stack would in a non-tail-recursive version! That is exactly right. Any non-tail recursive algorithm can be converted to a tail-recursive one by moving the "list of stack frames" from stack to heap and converting the "postprocessing" of recursive call result into a walk over that data structure.
Pragmatic note: The factorial example above illustrates a general technique. It is quite useless as is - for factorial function it is quite enough to cache the top-level fact n result, because calculation of fact n for a particular n only hits a unique series of (n,res) pairs of arguments to fact0 - if (n,1) is not cached yet, then none of the pairs fact0 is going to be called on are.
Note that in this example, when we went from non-tail-recursive factorial to a tail-recursive factorial, we exploited the fact that multiplication is associative and commutative - tail-recursive factorial execute a different set of multiplications than a non-tail-recursive one.
In fact, a general technique exists for going from non-tail-recursive to tail-recursive algorithm, which yields an algorithm equivalent to a tee. This technique is called "continuatuion-passing transformation". Going that route, you can take a non-tail-recursive memoizing factorial and get a tail-recursive memoizing factorial by pretty much a mechanical transformation. See Brian's answer for exposition of this method.
I'm not sure if there's a simpler way to do this, but one approach would be to create a memoizing y-combinator:
let memoY f =
let cache = Dictionary<_,_>()
let rec fn x =
match cache.TryGetValue(x) with
| true,y -> y
| _ -> let v = f fn x
cache.Add(x,v)
v
fn
Then, you can use this combinator in lieu of "let rec", with the first argument representing the function to call recursively:
let tailRecFact =
let factHelper fact (x, res) =
printfn "%i,%i" x res
if x = 0 then res
else fact (x-1, x*res)
let memoized = memoY factHelper
fun x -> memoized (x,1)
EDIT
As Mitya pointed out, memoY doesn't preserve the tail recursive properties of the memoee. Here's a revised combinator which uses exceptions and mutable state to memoize any recursive function without overflowing the stack (even if the original function is not itself tail recursive!):
let memoY f =
let cache = Dictionary<_,_>()
fun x ->
let l = ResizeArray([x])
while l.Count <> 0 do
let v = l.[l.Count - 1]
if cache.ContainsKey(v) then l.RemoveAt(l.Count - 1)
else
try
cache.[v] <- f (fun x ->
if cache.ContainsKey(x) then cache.[x]
else
l.Add(x)
failwith "Need to recurse") v
with _ -> ()
cache.[x]
Unfortunately, the machinery which is inserted into each recursive call is somewhat heavy, so performance on un-memoized inputs requiring deep recursion can be a bit slow. However, compared to some other solutions, this has the benefit that it requires fairly minimal changes to the natural expression of recursive functions:
let fib = memoY (fun fib n ->
printfn "%i" n;
if n <= 1 then n
else (fib (n-1)) + (fib (n-2)))
let _ = fib 5000
EDIT
I'll expand a bit on how this compares to other solutions. This technique takes advantage of the fact that exceptions provide a side channel: a function of type 'a -> 'b doesn't actually need to return a value of type 'b, but can instead exit via an exception. We wouldn't need to use exceptions if the return type explicitly contained an additional value indicating failure. Of course, we could use the 'b option as the return type of the function for this purpose. This would lead to the following memoizing combinator:
let memoO f =
let cache = Dictionary<_,_>()
fun x ->
let l = ResizeArray([x])
while l.Count <> 0 do
let v = l.[l.Count - 1]
if cache.ContainsKey v then l.RemoveAt(l.Count - 1)
else
match f(fun x -> if cache.ContainsKey x then Some(cache.[x]) else l.Add(x); None) v with
| Some(r) -> cache.[v] <- r;
| None -> ()
cache.[x]
Previously, our memoization process looked like:
fun fib n ->
printfn "%i" n;
if n <= 1 then n
else (fib (n-1)) + (fib (n-2))
|> memoY
Now, we need to incorporate the fact that fib should return an int option instead of an int. Given a suitable workflow for option types, this could be written as follows:
fun fib n -> option {
printfn "%i" n
if n <= 1 then return n
else
let! x = fib (n-1)
let! y = fib (n-2)
return x + y
} |> memoO
However, if we're willing to change the return type of the first parameter (from int to int option in this case), we may as well go all the way and just use continuations in the return type instead, as in Brian's solution. Here's a variation on his definitions:
let memoC f =
let cache = Dictionary<_,_>()
let rec fn n k =
match cache.TryGetValue(n) with
| true, r -> k r
| _ ->
f fn n (fun r ->
cache.Add(n,r)
k r)
fun n -> fn n id
And again, if we have a suitable computation expression for building CPS functions, we can define our recursive function like this:
fun fib n -> cps {
printfn "%i" n
if n <= 1 then return n
else
let! x = fib (n-1)
let! y = fib (n-2)
return x + y
} |> memoC
This is exactly the same as what Brian has done, but I find the syntax here is easier to follow. To make this work, all we need are the following two definitions:
type CpsBuilder() =
member this.Return x k = k x
member this.Bind(m,f) k = m (fun a -> f a k)
let cps = CpsBuilder()
I wrote a test to visualize the memoization. Each dot is a recursive call.
......720 // factorial 6
......720 // factorial 6
.....120 // factorial 5
......720 // memoizedFactorial 6
720 // memoizedFactorial 6
120 // memoizedFactorial 5
......720 // tailRecFact 6
720 // tailRecFact 6
.....120 // tailRecFact 5
......720 // tailRecursiveMemoizedFactorial 6
720 // tailRecursiveMemoizedFactorial 6
.....120 // tailRecursiveMemoizedFactorial 5
kvb's solution returns the same results are straight memoization like this function.
let tailRecursiveMemoizedFactorial =
memoize
(fun x ->
let rec factorialUtil x res =
if x = 0 then
res
else
printf "."
let newRes = x * res
factorialUtil (x - 1) newRes
factorialUtil x 1
)
Test source code.
open System.Collections.Generic
let memoize f =
let cache = new Dictionary<_, _>()
(fun x ->
match cache.TryGetValue(x) with
| true, y -> y
| _ ->
let v = f(x)
cache.Add(x, v)
v)
let rec factorial(x) =
if (x = 0) then
1
else
printf "."
x * factorial(x - 1)
let rec memoizedFactorial =
memoize (
fun x ->
if (x = 0) then
1
else
printf "."
x * memoizedFactorial(x - 1))
let memoY f =
let cache = Dictionary<_,_>()
let rec fn x =
match cache.TryGetValue(x) with
| true,y -> y
| _ -> let v = f fn x
cache.Add(x,v)
v
fn
let tailRecFact =
let factHelper fact (x, res) =
if x = 0 then
res
else
printf "."
fact (x-1, x*res)
let memoized = memoY factHelper
fun x -> memoized (x,1)
let tailRecursiveMemoizedFactorial =
memoize
(fun x ->
let rec factorialUtil x res =
if x = 0 then
res
else
printf "."
let newRes = x * res
factorialUtil (x - 1) newRes
factorialUtil x 1
)
factorial 6 |> printfn "%A"
factorial 6 |> printfn "%A"
factorial 5 |> printfn "%A\n"
memoizedFactorial 6 |> printfn "%A"
memoizedFactorial 6 |> printfn "%A"
memoizedFactorial 5 |> printfn "%A\n"
tailRecFact 6 |> printfn "%A"
tailRecFact 6 |> printfn "%A"
tailRecFact 5 |> printfn "%A\n"
tailRecursiveMemoizedFactorial 6 |> printfn "%A"
tailRecursiveMemoizedFactorial 6 |> printfn "%A"
tailRecursiveMemoizedFactorial 5 |> printfn "%A\n"
System.Console.ReadLine() |> ignore
That should work if mutual tail recursion through y are not creating stack frames:
let rec y f x = f (y f) x
let memoize (d:System.Collections.Generic.Dictionary<_,_>) f n =
if d.ContainsKey n then d.[n]
else d.Add(n, f n);d.[n]
let rec factorialucps factorial' n cont =
if n = 0I then cont(1I) else factorial' (n-1I) (fun k -> cont (n*k))
let factorialdpcps =
let d = System.Collections.Generic.Dictionary<_, _>()
fun n -> y (factorialucps >> fun f n -> memoize d f n ) n id
factorialdpcps 15I //1307674368000

Resources