10

ここで説明されているように、F# での関数合成の基本を理解しています。

たぶん、私は何かを見逃しています。>>and<<演算子は、各関数が 1 つの引数しかとらないという前提で定義されているようです。

> (>>);;
val it : (('a -> 'b) -> ('b -> 'c) -> 'a -> 'c) = <fun:it@214-13>
> (<<);;
val it : (('a -> 'b) -> ('c -> 'a) -> 'c -> 'b) = <fun:it@215-14>

ただし、私がやりたいことは、次のようなものです。

let add a b = a + b
let double c = 2*c
let addAndDouble = add >> double   // bad!

しかし、addの出力がdoubleの入力に必要なタイプであっても、それは拒否されます。

add を 1 つのタプル引数で書き直すことができることはわかっています。

let add (a,b) = a + b

または、最初の関数に可能な引数の数ごとに新しい演算子を書くことができます。

let inline (>>+) f g x y = g (f x y)
let doubleAdd = add >>+ double

しかし、それはばかげているようです!私が見逃したより良い方法はありますか?

4

3 に答える 3

12

あなたが望むことは完全に不合理ではありませんが、F# の型システム内で一般化された合成演算子の型を示す方法はありません。つまり、統一する良い方法はありません

(>>) : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c

(>>+) : ('a -> 'b -> 'c) -> ('c -> 'd) -> 'a -> 'b -> 'd

(無数の高アリティ バージョンは言うまでもありません)。したがって、独自の追加演算子を定義する以外に方法はありません。実際には、「指摘された」スタイルで書かれたコードlet f x y = add x y |> doubleは、ポイントフリー/「ポイントレス」よりも読みやすいことがよくありますlet f = add (>>+) double

于 2011-03-27T00:09:51.330 に答える
4

引数のスタックをスレッド化するのはどうですか?

let add = function x :: y :: t -> x + y :: t
let double = function x :: t -> 2 * x :: t

次に、任意のアリティ関数を構成できます。

let doubleAdd = add >> double

そしてそれは動作します:

> doubleAdd [7; 14]
42

(複数の入力パラメーターを使用した F# 関数構成も参照してください)

于 2011-04-21T02:22:18.450 に答える
4

上に投稿した>>とのタイプを見てください。<<例えば:

> (>>);;
val it : (('a -> 'b) -> ('b -> 'c) -> 'a -> 'c) = <fun:it@214-13>

2 つの関数と値 ( 'a) を取り、別の値を返します。2 つの関数と 2 つの値を取るものが必要です。したがって、 と の両方に正しい型シグネチャが>>あり<<ません。

あなたの実装はまったくばかげていません。F# のライブラリでは、要件がすぐに出てくるわけではないというだけです。このような独自の演算子を定義できる言語があることに感謝してください:)

于 2011-03-27T00:02:27.023 に答える