21

コンパイラが最適化するのに役立ちますか、それとも型シグネチャを追加するだけの余分な作業ですか? たとえば、次のようなことがよくあります。

foo :: a -> b
foo x = bar x
      where bar x = undefined

それよりも:

foo :: a -> b
foo x = bar x
      where bar :: a -> b
            bar x = undefined

トップレベルの型シグネチャを省略した場合、GHC は警告を表示します。したがって、警告が表示されなければ、自分のプログラムが正しいと確信できます。ただし、where 句で署名を省略しても、警告は発行されません。

4

4 に答える 4

22

Haskell で (派手な GHC 拡張機能を使用しないと) 型を記述できないローカル関数のクラスが存在します。例えば:

f :: a -> (a, Int)
f h = g 1
  where g n = (h, n)

これはaf型シグニチャの は外部から見ると多態的ですがf、内部からはそうではないためですf。ではg、それは未知の型であり、型ではなく(標準) Haskell は型言語で「これが定義されている関数の最初の引数と同じ型」を表現できません。

于 2012-05-15T23:18:55.580 に答える
20

多くの場合、where句の定義は、部分式が定義内で複数回発生する場合に繰り返しを避けるためのものです。このような場合、プログラマーは、ローカル定義をインライン部分式を書き出すための単純な代役と見なします。通常、インライン部分式を明示的に入力しないため、where定義も入力しません。入力を節約するためにそれを行っている場合、型宣言はすべての節約を台無しにしてしまいます。

Haskell の学習者にその形式の例を紹介することは非常に一般的であるように思われるwhereため、「通常のスタイル」はローカル定義の型宣言を与えないことであると考え続けています。少なくとも、それが Haskell を学んだ私の経験でした。それ以来、ブロックが必要なほど複雑な関数の多くはwhere、ローカル定義の型がわからないと不可解になることがわかったので、今は常にそれらを入力するように誤りを犯そうとしています。コードを書いている間は型が明らかだと思っていても、しばらく見ていなかった後にそれを読んでいると、それほど明白ではない場合があります。ほとんどの場合、頭の中で型推論を実行しなければならない 1 つか 2 つのインスタンスが、私の指のわずかな努力よりも重要です。

Ingo の回答は、意図的にローカル定義に型を与えない正当な理由を与えてくれますが、主な理由は、多くのプログラマーが、トップレベルの定義には型宣言を提供するがローカル定義には提供しないという経験則を同化していることだと思います。彼らは Haskell を学びました。

于 2012-05-16T01:05:10.787 に答える
11

多くの場合where、宣言は、単純な型または簡単に推測できる型を持つ短いローカルなものに使用されます。その結果、型を追加することは、人間やコンパイラにとって何のメリットもありません。

型が複雑な場合、または推論できない場合は、型を追加することをお勧めします。

whereモノモーフィックな型シグネチャを与えることでトップレベルの関数を高速化できますが、GHC はほとんどの場合定義をインライン化して最適化するため、節内のローカル定義にはそれほど有利ではありません。

于 2012-05-15T23:07:46.020 に答える
0

型シグネチャを追加すると、コードを高速化できます。たとえば、次のプログラム (フィボナッチ) を考えてみましょう。

result = fib 25 ;
-- fib :: Int -> Int
fib x = if x<2 then 1 else (fib (x-1)) + (fib (x-2))
  • 2 行目の注釈がなければ、0.010 秒かかります。走る。
  • アノテーションを使用するInt -> Intと、0.002 秒かかります。

これは、 について何も言わないとfib、 として型付けされるため発生します。つまり、実行時に、 /型クラスfib :: (Num a, Num a1, Ord a) => a -> a1を表すために関数間で追加のデータ構造 (「辞書」) を渡す必要があります。NumOrd

于 2012-05-15T23:07:16.127 に答える