Je suis en train d'appliquer le modèle de monade libre comme décrit dans F# for fun and profit pour mettre en œuvre l'accès aux données (pour Microsoft Azure Table Storage)Monad gratuit en F # avec le type de sortie générique
Exemple
Supposons que nous avons trois tables de base de données et trois dao foo, bar, Baz:
Foo Bar Baz
key | col key | col key | col
--------- --------- ---------
foo | 1 bar | 2 |
Je veux sélectionner foo avec key = "toto" et un bar avec key = "bar" pour insérer un Baz avec key = "baz" et 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()))))
Au sein de la fonction interprète
Select
résultats dans un appel de fonction qui prend unekey : string
et retourne unobj
Insert
résultats dans un appel de fonction qui prend unobj
et retourneunit
Pro Blem
je définissais deux opérations Select
et Insert
en plus de Done
mettre fin au calcul:
type StoreOp<'T> =
| Select of string * ('T -> StoreOp<'T>)
| Insert of 'T * (unit -> StoreOp<'T>)
| Done of 'T
Pour chaîne StoreOp de Je suis en train de mettre en œuvre la fonction de liaison correcte:
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
Cependant, le compilateur f # me prévient correctement que:
The type variable 'T1 has been constrained to be type 'T2
Pour cette mise en œuvre de bindOp le type est fixé tout au long du calcul, donc au lieu de:
Foo > Bar > unit
tout ce que je peux exprimer est:
Foo > Foo > Foo
Comment dois-je modifier la définition de StoreOp et/ou bindOp pour travailler avec différents types tout au long du calcul?
Je peux vous indiquer la raison exacte de cette erreur dans votre code 'bindOp', mais la raison racine est votre type' StoreOp'. Si vous le regardez de près, vous verrez qu'il ne peut qu'exprimer des chaînes d'opérations sur le même type. –
Ne serait-il pas possible d'éviter tous ces niveaux d'indirection et de faire les choses simples de CRUD dans quelque chose comme un [Script de Transaction] (https://martinfowler.com/eaaCatalog/transactionScript.html)? C'est similaire à ce que Tomas Petricek décrit dans le dernier paragraphe de sa [réponse] (http://stackoverflow.com/a/41668459/467754). Voir aussi [Pourquoi la Monad gratuite n'est pas gratuite] (https://www.youtube.com/watch?v=U0lK0hnbc4U). –
L'implémentation actuelle est un simple ensemble de fonctions CRUD impératives. S'il vous plaît voir le commentaire ci-dessous pour la motivation. – dtornow