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