サーチ…
共通の演算子を使用して値と関数を構成する方法
オブジェクト指向プログラミングでは、一般的な作業はオブジェクト(値)を作成することです。関数型プログラミングでは、関数と同様に値を構成するのが一般的な作業です。
+
、 -
、 *
、 /
などの演算子を使用して、他のプログラミング言語の経験から値を構成しています。
価値構成
let x = 1 + 2 + 3 * 2
関数型プログラミングは値だけでなく値も構成するので、意外なことではない>>
、 <<
、 |>
や<|
。
機能構成
// val f : int -> int
let f v = v + 1
// val g : int -> int
let g v = v * 2
// Different ways to compose f and g
// val h : int -> int
let h1 v = g (f v)
let h2 v = v |> f |> g // Forward piping of 'v'
let h3 v = g <| (f <| v) // Reverse piping of 'v' (because <| has left associcativity we need ())
let h4 = f >> g // Forward functional composition
let h5 = g << f // Reverse functional composition (closer to math notation of 'g o f')
F#
では、以下の理由により、配管が逆配管よりも優先されます。
- 型推論は(一般的に)左から右に流れるので、値と関数が左から右に流れるのは自然です
-
<|
<<
は正しい連想性を持つべきですが、F#
では左結合であり、 - 順方向と逆方向の配管を混在させることは、同じ優先順位を持つために一般的に機能しません。
モナド組成
モナド( Option<'T>
やList<'T>
)は関数型プログラミングでよく使われているので、モナド( >>=
、 >=>
、 <|>
、 <*>
。
let (>>=) t uf = Option.bind uf t
let (>=>) tf uf = fun v -> tf v >>= uf
// val oinc : int -> int option
let oinc v = Some (v + 1) // Increment v
// val ofloat : int -> float option
let ofloat v = Some (float v) // Map v to float
// Different ways to compose functions working with Option Monad
// val m : int option -> float option
let m1 v = Option.bind (fun v -> Some (float (v + 1))) v
let m2 v = v |> Option.bind oinc |> Option.bind ofloat
let m3 v = v >>= oinc >>= ofloat
let m4 = oinc >=> ofloat
// Other common operators are <|> (orElse) and <*> (andAlso)
// If 't' has Some value then return t otherwise return u
let (<|>) t u =
match t with
| Some _ -> t
| None -> u
// If 't' and 'u' has Some values then return Some (tv*uv) otherwise return None
let (<*>) t u =
match t, u with
| Some tv, Some tu -> Some (tv, tu)
| _ -> None
// val pickOne : 'a option -> 'a option -> 'a option
let pickOne t u v = t <|> u <|> v
// val combine : 'a option -> 'b option -> 'c option -> (('a*'b)*'c) option
let combine t u v = t <*> u <*> v
結論
新しい関数型プログラマーにとっては、演算子を使った関数の構成は不透明で不明瞭に見えるかもしれませんが、それはこれらの演算子の意味が値を扱う演算子ほどよく知られていないためです。しかし、 |>
、 >>
、 >>=
、 >=>
を使ったいくつかのトレーニングでは、 +
、 -
、 *
、および/
を使うほど自然になります。
F#でLatebindingを使用していますか?オペレーター
F#
ような静的型言語では、コンパイル時によく知られている型を扱います。タイプ・プロバイダを使用して型保証型の外部データ・ソースを使用します。
しかし、時折、( C#
dynamic
なようdynamic
)遅延バインディングを使用する必要があります。たとえば、明確に定義されたスキーマを持たないJSON
ドキュメントを扱う場合などです。
レイトバインドの作業を簡素化するため、 F#
は動的検索演算子をサポートしてい?
?<-
。
例:
// (?) allows us to lookup values in a map like this: map?MyKey
let inline (?) m k = Map.tryFind k m
// (?<-) allows us to update values in a map like this: map?MyKey <- 123
let inline (?<-) m k v = Map.add k v m
let getAndUpdate (map : Map<string, int>) : int option*Map<string, int> =
let i = map?Hello // Equivalent to map |> Map.tryFind "Hello"
let m = map?Hello <- 3 // Equivalent to map |> Map.add "Hello" 3
i, m
レイトバインディングのF#
サポートはシンプルで柔軟性があることが判明しました。
Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow