42

Haskell での並列および並行プログラミングに関する Simon Marlow の本からいくつかの例を試してみたところ、よくわからない興味深い動作に出くわしました。これは、GHC の内部動作のいくつかを理解しようとしている私に関するものです。

REPLで次のことをするとしましょう:

λ» let x = 1 + 2 :: Int
λ» let z = (x,x)
λ» :sprint x
x = _
λ» :sprint z
z = (_,_)
λ» seq x ()
()
λ» :sprint z
z = (3,3)

z がすでに WHNF に評価されていることを除けば、これは私が予想したこととほぼ同じです。同様のプログラムを作成して、ファイルに入れましょう。

module Thunk where

import Debug.Trace

x :: Int
x = trace "add" $ 1 + 2

z :: (Int,Int)
z = (x,x)

GHCiでそれをいじります:

λ» :sprint x
x = _
λ» :sprint z
z = _
λ» seq x ()
add
()
λ» :sprint z
z = _
λ» seq z ()
()
λ» z
(3,3)

したがって、これは少し異なる動作をします:z事前に WHNF に評価されません。私の質問は:

ファイルから定義をロードするときではなく、z行うときに REPL で WHNF に評価されるのはなぜですか。let z = (x,x)私の疑惑は、それがパターンバインディングと関係があるということですが、明確にするためにそれをどこで調べたらよいかわかりません (完全に間違っているかもしれません)。ファイルの例のように何らかの形で動作することを期待していました。

なぜこれが起こるのか、ポインタや簡単な説明はありますか?

4

1 に答える 1

2

はコンストラクターであるため(,)、違いは Haskell のセマンティクスに違いはありません (:sprintは内部サンク実装の詳細へのアクセスを提供するため、カウントされません)。したがって、これは、GHC が(x,x)異なる位置でコンパイルするときにどの最適化とトレードオフを行うかという問題です。これらの場合、他の誰かが正確な理由を知っているかもしれません。

于 2015-03-03T07:18:51.650 に答える