27

私は最近 F# の学習を開始し、次のような単純な例のカリー化された関数に出くわしました。

p価格に販売個数を掛けて売上を計算する関数を考えてみましょうn

let sales (p,n) = p * (float n);;

この関数の型は次のように与えられます

val sales : p:float * n:int -> float

つまり、floatandのペアを取り、 aintを返しますfloat

代わりに、これをカリー化された関数として書くことができます

let salesHi p n = p * (float n);;

この関数の型は次のように与えられます

val salesHi : p:float -> n:int -> float

つまり、 を取り、toの関数float返します。intfloat

単純なケースでは、これは違いがないようです

sales (0.99, 100);;
salesHi 0.99 100;;

どちらも与える

val it : float = 99.0

ただし、カリー化された関数を使用すると、特定のアイテムの価格をフィードして新しい関数を取得できます。例えば

let salesBeer =  salesHi 5.99;;
let salesWine =  salesHi 14.99;;

次に、salesBeer 2与え11.98salesWine 2与え29.98ます。

+また、 などの組み込み演算子が関数として定義されていることに気付きました。たとえば、次のように記述できます。

let plus2 = (+) 2;
List.map plus2 [1;3;-1];;

そして得る

val it : int list = [3; 5; 1]

これは良いことのようです。したがって、引数を取る命令型言語で関数を実装したい場合n > 1、たとえば F# では常にカリー化された関数を使用する必要があります (引数が独立している限り)。または、必要に応じて、単純なルートを取り、n後でタプルとカレーを使用して通常の関数を使用する必要がありますか? または、他の何か?

F# プログラマーは、カリー化された形式で関数を作成するか、タプルで通常の関数を使用するかをどのように決定しますか?

4

4 に答える 4

32

カリー化された形式とタプル形式のどちらかを選択する場合、主に考慮すべきことは、引数として受け取るタプルが何かを意味するかどうかです。

タプル形式。たとえばfloat * float、範囲を表す場合は、タプル形式を使用することをお勧めします。

let normalizeRange (lo, hi) = if hi < lo then (hi, lo) else (lo, hi)
let expandRange by (lo, hi) = (lo - by, hi + by)

これの良いところは、範囲で機能する関数を作成できることです。たとえば、次のように書くことができます。

randomRange() |> normalizeRange |> expandRange 10

カレー形態。一方、すべての引数のタプルが何らかの有用な意味を持つスタンドアロンの値でない場合は、カリー化された形式の方が適しています。たとえば、累乗関数- 2 つの引数は累乗する数値と指数ですが、プログラムの他の場所でpown 2.0 10タプルを使用することはほとんどありません。(2.0, 10)

カリー化された形式は、"より重要な" 引数が 1 つある場合にも役立ちます。これは、パイプラインを使用できるためです。たとえば、List.mapこれを許可するにはカリー化する必要があります。

[1 .. 10] |> List.map (fun n -> n + 1)
于 2013-09-10T14:31:38.023 に答える
2

タプル形式は実際には少し危険です。ALGOL スタイルの言語 (一般的な言語の 90%) に似ているように見えるかもしれませんが、動作が異なります。

このことを考慮:

foo bar(x,y)

この構文を使用できるすべての ALGOL スタイルの言語では、これは「 を引数として呼び出し、結果を に渡すbar」ことを意味します ( 2.* Pythonのように構文である必要はありません)。xyfoofooprint

ただし、Lambda スタイルの言語 (ML、Haskell、F# など) では、これは「引数として呼び出しfoobarタプルを引数として結果 (関数) を呼び出す」ことを意味(x,y)します。

Lambda スタイルの言語を初めて使用する場合、これは非常に混乱する可能性があります。現在、カレー形式を使用していた場合、同等のものは次のようになります。

foo bar x y

これは - と同じくらい間違っていますfoo bar(x,y)が、混乱するほどではありません! barLambda スタイルの言語に慣れていないプログラマーでも、これが で呼び出される最初の関数ではないことを簡単に理解できますfoo bar x y。エラーはすぐに解消されます。

于 2013-09-10T16:16:52.820 に答える