2017-03-15 3 views
4

Kleisli組成演算子>=>は、特殊な関数の構成が必要な多くの状況で便利です。 >>のように動作しますが、単純な関数を作成する代わりに、'a -> m<'b>という特殊なプロパティを与えます。mは、モナドのような型または関数の戻り値のプロパティです。 より広いF#コミュニティにおけるこの実践の証拠は、例えば以下に見出すことができる。 Scott WlaschinのRailway oriented programming (part 2)には、Result<'TSuccess,'TFailure>型を返す関数の構成が含まれています。F#で魚を作る#

let mkFish bind f g a = bind g (f a) 

これはつまり、一般的に1つのshouldnの注意点を見事に動作します:バインドがあるのところ、また魚がなければならない、私はバインド機能自体に正規のKleisliオペレータの定義let (>=>) f g a = f a >>= gをパラメータしようとしていること

推論特別な演算子をユーザー向きのコードで解き放つことはできません。私は...

module Option = 
    let (>=>) f = mkFish Option.bind f 
    let odd i = if i % 2 = 0 then None else Some i 
    let small i = if abs i > 10 then None else Some i 
    [0; -1; 9; -99] |> List.choose (odd >=> small) 
    // val it : int list = [-1; 9] 

をオプションを返す関数を作成することができ...または私は、スタックの2つの一番上の値に関数適用を工夫し、私が運転していたデータ構造を参照することなく戻って結果をプッシュすることができます明示的に:

module Stack = 
    let (>=>) f = mkFish (<||) f 
    type 'a Stack = Stack of 'a list 
    let pop = function 
    | Stack[] -> failwith "Empty Stack" 
    | Stack(x::xs) -> x, Stack xs 
    let push x (Stack xs) = Stack(x::xs) 
    let apply2 f = 
     pop >=> fun x -> 
     pop >=> fun y -> 
     push (f x y) 

しかし、何を私に気が署名val mkFish : bind:('a -> 'b -> 'c) -> f:('d -> 'b) -> g:'a -> a:'d -> 'cは意味をなさないということです。型変数は混乱した順序であり、あまり一般的ではありません('aは関数でなければなりません)、私はそれに自然な注釈を付けることはできません。 正式なファンクタとモナドがない場合、どうやって抽象化できますか?各タイプに対して明示的にKleisli演算子を定義する必要はありませんか?

答えて

4

あなたはHigher Kindsのない自然な方法ではできません。現在の.NET型システムでは表現できないです

let (>=>) (f:'T -> #Monad<'U>``) (g:' U -> #Monad<'V>) (x:'T) : #Monad<'V> = bind (f x) g 

:魚の

署名は次のようになります。

実際には一般的な魚オペレーターを使用したい場合は、F#+を使用して静的な制約を使用して定義することができます。第5回code sample hereを見ると、さまざまな種類のアクションが表示されます。

もちろん、あなた自身で定義することもできますが、最も一般的なシナリオでは適切に動作させるために、コードすることがたくさんあります。あなたはライブラリからコードを取得することができますか、私は小さな(しかし、限られた)コードサンプルを書くことができますしたい場合。

一般的な魚はthis lineで定義されています。

私は一般的に、演算子を使用するときは一般的な関数がないと感じます。なぜなら、発見したように、モジュールを開いたり閉じたりする必要があるからです。関数のように、モジュール名の前に接頭辞を付けるのではなく、演算子でも同様に行うことができます(Option.(>=>)のような)が、演算子を使用する目的を全滅させます。

+0

頻繁に静的に解決されたタイプのパラメータがレスキューに!私はこれが唯一可能な答えだと思います。少なくとも、グローバルな汎用演算子の明白な使用例では。私はちょっとしたアドホックを考えていました。ここに私のバインドがあり、私にKleisliを与えました。しかし、特注のオペレータ定義で関数アプリケーションを書き留める努力はそれほどありません。 – kaefer

関連する問題