Próbuję zastosować swobodny monada wzór, jak to opisano w F# for fun and profit do realizacji dostępu do danych (dla Microsoft Azure Table Storage)bezpłatny Monada w F # z wyjścia typu generic
Przykład
Załóżmy mamy trzy tabele bazy danych i trzy Dao za foo Bar, baz:
Foo Bar Baz
key | col key | col key | col
--------- --------- ---------
foo | 1 bar | 2 |
Chcę wybrać foo with key = "foo" i bar z key = "bar", aby wstawić baz z key = "baz" i kol = 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()))))
W funkcji tłumacza
Select
powoduje wywołanie funkcji, które odbywają siękey : string
i zwracaobj
Insert
wyniki wywołania funkcji, która pobieraobj
i powracaunit
Pro blem
zdefiniowałem dwie operacje Select
i Insert
oprócz Done
aby zakończyć obliczenia:
type StoreOp<'T> =
| Select of string * ('T -> StoreOp<'T>)
| Insert of 'T * (unit -> StoreOp<'T>)
| Done of 'T
W celu łańcuch StoreOp na Staram się realizować poprawne działanie wiąże:
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 ->
f t
let (>>=) = bindOp
Jednak kompilator f # prawidłowo ostrzega mnie, że:
The type variable 'T1 has been constrained to be type 'T2
Na tej realizacji bindOp typ jest stała w całym obliczeń, więc zamiast:
Foo > Bar > unit
mogę wyrazić to:
Foo > Foo > Foo
Jak należy zmodyfikować definicję StoreOp i/lub bindOp do pracy z różnymi typami w trakcie obliczeń?
Mogę wskazać ci dokładną przyczynę tego błędu w kodzie "bindOp', ale podstawową przyczyną jest twój typ" StoreOp ". Jeśli przyjrzysz się temu uważnie, zobaczysz, że może tylko wyrazić łańcuch operacji na tym samym typie. –
Czy nie byłoby możliwe uniknięcie wszystkich poziomów pośrednich i zrobienie prostych rzeczy w stylu CRUD w coś w rodzaju [Skryptu transakcyjnego] (https://martinfowler.com/eaaCatalog/transactionScript.html)? Jest to podobne do tego, co Tomas Petricek opisuje w ostatnim akapicie swojej [odpowiedzi] (http://stackoverflow.com/a/41668459/467754). Zobacz także [Dlaczego bezpłatna monada nie jest darmowa] (https://www.youtube.com/watch?v=U0lK0hnbc4U). –
Obecna implementacja jest prostym zestawem imperatywnych funkcji CRUD. Zobacz motyw poniżej. – dtornow