2011-11-30 22 views
9
data Thing = Thing {a :: Int, b :: Int, c :: Int, (...) , z :: Int} deriving Show 

foo = Thing 1 2 3 4 5 (...) 26 
mkBar x = x { c = 30 } 

main = do print $ mkBar foo 

fooをこのように変更したときにコピーされるのは何ですか?構造体の一部を直接変更するのではなく、レコードの更新は内部的にどのように動作しますか?

Data Thing = Thing {a :: IORef Int, b :: IORef Int, (...) , z :: IORef Int} 
instance Show Thing where 
(...something something unsafePerformIO...) 

mkFoo = do a <- newIORef 1 
      (...) 
      z <- newIORef 26 
      return Thing a b (...) z 
mkBar x = writeIORef (c x) 30 

main = do foo <- mkFoo 
      mkBar foo 
      print foo 

最適化を使用してコンパイルすると、この動作が変更されますか?

+4

何か、何か、何か、 'unsafePerformIO'。何か、何か、何か、完全。 –

答えて

8

最初の例では、変更されていないIntコンポーネントへのポインタがコピーされます(コンストラクタタグも同様です)。 Intか1つのポインタへのポインタがコピーされるかどうかはそれほど違いはありませんが、コンポーネントが大きな構造体だった場合には大きな違いはありません。

フィールドは厳密ではないため、afaikは最適化とは関係なく動作します。フィールドが厳密で最適化されていれば、それらはコンストラクタに展開され、生のInt#の値がコピーされます。

第2の例では、何もコピーされず、IORefの内容が上書きされます。ダニエルの答えに拡大すること

8

、あなたはそれが全体の構造をコピーするには、フィールドの結果を更新することはおそらくケースです

data Foo = Foo Int Int 
update (Foo a b) x = Foo x b 
2

としてちょうど約同じよう

data Foo = Foo {a::Int, b::Int} 
update foo x = foo{a=x} 

と考えることができます。しかし、コンパイラがその構造が単一のスレッド方法で使用されていることを証明できれば、その場で更新を行うことができます。私はこれを行う実装についてはわかりませんが、1ビットの参照カウントでそれを行うと想像することができます。

+0

私はクリーンはシングルスレッド化がその型システムに組み込まれていると思います。しかし、CleanはHaskellの実装ではありません。 – nponeccop

+0

はい、クリーンには一意性のタイプがあります。アレイ。 – augustss

関連する問題