7

コード内で数回使用される haskell の nullary 関数があるとします。常に一度だけ評価されますか?私はすでに次のコードをテストしました:

sayHello :: Int
sayHello = unsafePerformIO $ do
    putStr "Hello"
    return 42

test :: Int -> [Int]
test 0 = []
test n = (sayHello:(test (n-1)))

テスト 10 を呼び出すと、"Hello" が 1 回だけ書き込まれるため、最初の評価後に関数の結果が格納されていることを示しています。私の質問は、それは保証されていますか? 異なるコンパイラで同じ結果が得られますか?

編集 unsafePerformIO を使用した理由は、sayHello が複数回評価されるかどうかを確認するためです。私のプログラムではそれを使用しません。通常、私は sayHello が評価されるたびにまったく同じ結果になることを期待しています。しかし、これは時間のかかる操作なので、この方法でアクセスできるかどうか、または複数回評価されないようにするために必要な場合はいつでも引数として渡す必要があるかどうかを知りたかったのです。

test _ 0 = []
test s n = (s:(test (n-1)))
...
test sayHello 10

答えによると、これを使用する必要があります。

4

3 に答える 3

17

ヌル関数のようなものはありません。Haskell の関数は引数を 1 つだけ持ち、常に type を持ち... -> ...ます。sayHelloは値ですIntが、関数ではありません。詳細については、この記事を参照してください。

保証について: いいえ、保証はありません。Haskell のレポートでは、Haskell は非厳密であると指定されています。そのため、最終的にどのような値に還元されるかがわかりますが、特定の評価戦略はありません。GHC が一般的に使用する評価戦略は遅延評価、つまり共有を伴う非厳密な評価ですが、それについての強い保証はありません。

さまざまな例外もあります。たとえば、foo :: Num a => aポリモーフィックであるため、おそらく共有されません (実際の関数にコンパイルされます)。純粋な値が同時に複数のスレッドによって評価される場合があります (この場合は、unsafePerformIO明示的noDuplicateにそれを回避するために使用されるため、発生しません)。したがって、プログラムを作成するときは、一般的に怠惰を期待できますが、なんらかの保証が必要な場合は、非常に注意する必要があります。レポート自体は、プログラムがどのように評価されているかについて実際には何も提供しません。

unsafePerformIOもちろん、保証の方法はさらに少なくなります。「危険」と言われるのには理由があります。

于 2013-06-13T03:37:51.107 に答える
5

のようなトップレベルの引数のない関数sayHelloは、Constant Applicative Forms と呼ばれ、常にメモ化されます (少なくとも GHC では - http://www.haskell.org/ghc/docs/7.2.1/html/users_guide/profiling.htmlを参照してください)。CAF をグローバルに共有しないようにするには、仮引数を渡したり、最適化をオフにしたりするなどのトリックに頼る必要があります。

編集:上記のリンクから引用 -

Haskell は遅延言語であり、特定の式は一度しか評価されません。たとえば、次のように書く とx = nfib 25、 thenxは 1 回だけ評価され (存在する場合)、その後の要求xはキャッシュされた結果をすぐに確認できます。この定義xは、引数がないため、CAF (Constant Applicative Form) と呼ばれます。

于 2013-06-13T04:31:05.730 に答える