I am trying to apply the free monad template as described in F # for fun and profit in order to implement data access (for Microsoft Azure Table Storage)
Example
Suppose we have three database tables and three Tao Foo, Bar, Baz:
Foo Bar Baz key | col key | col key | col --------- --------- --------- foo | 1 bar | 2 |
I want to select Foo with key = "foo" and Bar with key = "bar" to insert Baz with key = "baz" and col = 3
Select<Foo> ("foo", fun foo -> Done foo) >>= (fun foo -> Select<Bar> ("bar", fun bar -> Done bar) >>= (fun bar -> Insert<Baz> ((Baz ("baz", foo.col + bar.col), fun () -> Done ()))))
In interpreter function
Select results in a function call that takes key : string and returns objInsert leads to a function call that takes obj and returns unit
Problem
I defined two Select and Insert operations in addition to Done to complete the calculation:
type StoreOp<'T> = | Select of string * ('T -> StoreOp<'T>) | Insert of 'T * (unit -> StoreOp<'T>) | Done of 'T
To create a StoreOp chain, I am trying to implement the correct binding function:
let rec bindOp (f : 'T1 -> StoreOp<'T2>) (op : StoreOp<'T1>) : StoreOp<'T2> = match op with | Select (k, next) -> Select (k, fun v -> bindOp f (next v)) | Insert (v, next) -> Insert (v, fun () -> bindOp f (next ())) | Done t -> ft let (>>=) = bindOp
However, the f # compiler correctly warns me that:
The type variable 'T1 has been constrained to be type 'T2
For this bindOp implementation, the type is fixed in all calculations, so instead of:
Foo > Bar > unit
all i can express is:
Foo > Foo > Foo
How do I change the definition of StoreOp and / or bindOp to work with different types during computation?