3

関数 addOne を作成するために部分的に適用する関数 add があります。

add :: Int -> (Int -> Int)
add x y = x + y

addOne は明示的なパラメーターで定義できます

addOne :: Int -> Int
addOne y = add 1 y

または明示的なパラメーターなし

addOne :: Int -> Int
addOne = add 1

4 つの質問があります。

  1. 明示的なパラメーターなしで新しい関数を定義できるのはなぜですか?
  2. これら2つの定義に違いはありますか?
  3. パラメータなしで関数を定義できる時期はいつわかりますか?
  4. どの定義が優先され、いつですか?
4

2 に答える 2

5
  1. というのは、つまり、addOne y = add 1 y常にただあるからです。これをイータ等価と呼びます。だから。addOne = \y -> add 1 y\x -> f xfaddOne = add 1

  2. いいえ

  3. いつも。関数パラメーターは、ラムダのシンタックス シュガーにすぎません。

    add :: Int -> Int -> Int
    add = \x y -> x + y
    

    変数バインディングを完全に削除できるかどうかは別の問題です。

  4. 余分な名前の導入を避けるため、可能な場合は常に "eta reduce" (つまり、バインドされた式の関数適用と一致する場合に、関数バインドの右端のバインドされた変数を削除する) を行うと便利です。

于 2014-10-23T17:00:14.753 に答える
4

Haskell を使用するために学ぶ必要がある関数型プログラミングの基本概念の 1 つは、関数は単なる一種の値であり、定義は単なる名前であるということです。関数変数の間に明確な区別があり、関数定義が変数定義と完全に異なる手続き型言語とは異なります。

したがって、次のような変数定義

addOne :: Int -> Int
addOne = add 1

は式の名前を追加するだけなadd 1ので、 として参照できますaddOne。変数宣言と同じです。[1] その変数の値が関数であるという事実は、Haskell の観点からはほとんど偶然です。

あなたのadd定義:

add :: Int -> (Int -> Int)
add x y = x + y

も変数定義です。これは、Haskell が提供するちょっとした構文糖衣です。

add :: Int -> Int -> Int
add = \ x -> \ y -> x + y

そのほうが読みやすいという説。しかし、それはただの砂糖です。他の言語のように必要になることはありません (以下の [1] を除く)。

[1]:恐るべき単型性の制限ここにも登場します。アイデアはただ: 関数定義では、RHS はコンピューターによって何度も実行されます (関数を呼び出した回数だけ)。あなたはおそらく他の言語からこれを認識しています。モノモーフィックな変数定義では、RHS は多くても 1 回実行されます。これは、他の言語の動作と同様です。ただし、ポリモーフィック変数は多くの場合、関数定義のように動作し、RHS は変数の値がアクセスされる回数だけ実行されます。したがって、Haskell は、多相型シグネチャを持っていない限り (つまり、「自分が何をしているのかわかっているので、この変数を多相にすることを許可する」と言う)、または左側に引数を持っていない限り、多相定義を許可しません (つまり、「のように、RHS を何度も実行する必要があります)。

于 2014-10-23T17:30:36.643 に答える