2016-11-18 4 views
3
タイトルはOK、それを説明し、私は次のコードについて持っているん

全くわからない:計算の応用的ファンクタ対表現やものではありません

paket.dependencies:

source https://www.nuget.org/api/v2 
nuget fsharpx.extras 
nuget mongodb.driver 

some.fsx:

#r @".\packages\MongoDB.Bson\lib\net45\MongoDB.Bson.dll" 
#r @".\packages\MongoDB.Driver\lib\net45\MongoDB.Driver.dll" 
#r @".\packages\MongoDB.Driver.Core\lib\net45\MongoDB.Driver.Core.dll" 

#r @".\packages\FSharpX.Extras\lib\net45\FSharpX.Extras.dll" 


open MongoDB 
open MongoDB.Driver 
open MongoDB.Bson 
open MongoDB.Bson.Serialization 

open FSharpx.Choice 

let private createClient (connectString:string) = MongoClient(connectString) 
let CreateClient = protect createClient 

let private getDb name (client:IMongoClient) = client.GetDatabase(name) 
let GetDB1 name client = 
    choose { 
     let! c = client 
     return! (protect (getDb name) c) 
    } 

let GetDB2 name (client:Choice<IMongoClient, exn>) = 
    protect (getDb name) 
    <!> client 

この「excersise」のポイントは、GetDB1と同じように動作するようにGetDB1を作成することでしたが、演算子(アプリケーション?)を使用していましたが、現時点ではこれを管理できません。

上記のコードはコンパイルされますが、 GetDB1とGetDB2のための署名は等しくない、とイムは明らかに何かない権利をやって。

val GetDB1 : 
    name:string -> 
    client:Choice<#MongoDB.Driver.IMongoClient,exn> -> 
     Choice<MongoDB.Driver.IMongoDatabase,exn> 

val GetDB2 : 
    name:string -> 
    client:Choice<MongoDB.Driver.IMongoClient,exn> -> 
     Choice<Choice<MongoDB.Driver.IMongoDatabase,exn>,exn> 

私はいくつかのバージョンとGetDB2で物事の注文を試してみましたが、私は多かれ少なかれ常に上記と同じシグネチャで終了します。

私が最初に持っていた一般的なアイデアは、必要なものを実行し、例外処理(プロテクト)を追加し、それに応じて「ラップ」と「アンラップ」を行うことでした。

もちろん、まったく正しいアイデアではないかもしれません。

誰かが今後の調査、コード例など何かを指示することができますか?任意の型の任意のコメントは、この点;-)

FSharpx doc

補遺と思い

で実際に歓迎しているが、MongoDBの依存関係なしに、上記とほぼ同じである必要があり、次の。

#r @".\packages\FSharpX.Extras\lib\net45\FSharpX.Extras.dll" 

type DataBase = 
    { 
     Name: string 
    } 

type Client = 
    { 
     connectString: string 
    } with member this.GetDatabase name = { 
         Name = name 
        } 

open FSharpx.Choice 
let private createClient (connectString:string) = { 
    connectString= connectString 
} 

let CreateClient = protect createClient 

let private getDb name (client:Client) = client.GetDatabase name 

let GetDB1 name client = 
    choose { 
     let! c = client 
     return! (protect (getDb name) c) 
    } 

let GetDB2 name client = 
    protect (getDb name) 
    <!> client 
+0

おそらく、これを[MCVE](http://stackoverflow.com/help/mcve)として表現できますか?私はこの質問を研究するためにMongoDBを手探りする気がしません。 –

+1

F#で法律上の演算子ではないHaskellの '<$>'の代わりに、F# ''のBTWがよく使われます。これは単純に 'map'のインディックスバージョンです(Haskellの' fmap')。 –

+0

@ MarkSeemann hehe。それは実際にはMCVEです。それは、ここでモンゴと仲良くする必要はありません;-)上記のランは、モンゴブがインストールされていない状態で実行されます。しかし、私は骨MCVEにいくつかもっとやろうとします... –

答えて

5

あなたはmapある<!>演算子を使用しているので、あなたはここで種類の配合を得ています。これは、署名('T -> 'U) -> Choice<'T,'Failure> -> Choice<'U,'Failure>、すなわち機能fを地図内部choiceタイプとして使用される有する

let map f = function 
    | Choice1Of2 value = Choice1Of2 (f value) 
    | Choice2Of2 fail = Choice2Of2 fail 

:それは次のように定義されています。例:

map (sprintf "%d") 

は、タイプがChoice<int, 'Failure> -> Choice<string, 'Failure>です。これは、Choiceタイプを使用しない関数を適用するのに適しています.1つの可能な障害点があり、それはmapの呼び出しの前に発生しました。

ただし、次の関数はChoiceタイプを生成しますが、Choiceタイプではありません。これは、エラーを伝播させたいことを意味します。値にエラーがある場合は、それを選択します。値が正常ですが、関数にエラーがある場合は、それを使用してください。すべて成功したら、それを使用してください。これには、2つのエラータイプが同じでなければなりません。これは(exn)です。署名('T -> Choice<'U,'Failure>) -> Choice<'T,'Failure> -> Choice<'U,'Failure>

let bind f = function 
    | Choice1Of2 value = f value 
    | Choice2Of2 fail = Choice2Of2 fail 

これは次のように定義されたbind動作を、説明されています。

bindmapと非常によく似ていますが、後者では結果がChoice1Of2になります。マップされた機能は常に成功します。 FSharpXで

、あなたは|>様オペレータ>>=、または<|様オペレータ<<=bindにアクセスすることができます。

最後に、protectは、スローされた例外をChoice2Of2 exnにキャッチするファンシーな方法です。渡された関数の型が'T -> 'Uであるという点でmapに似ていますが、この関数は例外をスローする可能性もあり、渡される型はではなく a Choiceです。

let protect f x = 
    try 
     Choice1Of2 (f x) 
    with 
     exn -> Choice2Of2 exn 

ので、その署名が('T -> 'U) -> 'T -> Choice<'U, exn>です:protectはこのような何かに定義されています。

すべての機能の実装方法の詳細については、the source of this computation expressionを参照してください。


これをすべてまとめると、あなたの例が間違っていた理由がわかります。

  • getDb nameClient -> DataBase
  • protect (getDb name)関数であるClient -> Choice<DataBase, exn>
  • map (protect (getDb name))
  • 関数でmapChoice内部動作するため、従って関数Choice<Client, exn> -> Choice<Choice<DataBase, exn>, 'Failure>あります。あなたがmapをしたい'T -> 'Uあなたのマッピング機能は、署名を持っている場合、あなたが望むもの

は、しかし、一般的に、

let GetDB name client = 
    bind (protect (getDb name)) client 

またはオペレータの形で、

let GetDB name client = client >>= protect (getDb name) 

です。 'T -> Choice<'U, 'Failure>の場合は、bindが必要です。

+0

最後の文章は.... ;-)ありがとう! –

関連する問題