haskell-jp / questions #106 at 2024-08-03 16:51:47 +0900

UNPACK pragma の質問です。通常は次のように使うと思います:
data TestA = TestA
  { aA :: {-# UNPACK #-} !Int,
    bA :: {-# UNPACK #-} !Int
  }

フィールドが一般の型 a の場合、以下の UNPACK は効果がありますか? (たとえば`TestB Int` 型は unpack されますか):
data TestB a = TestB
  { aB :: {-# UNPACK #-} !a,
    bB :: {-# UNPACK #-} !a
  }

TestB のコンパイル時警告では Ignoring.. とあるので、 UNPACK されない気がしています (確認用 playground: https://play.haskell.org/saved/8gaATevZ)
コンパイラーが言っているように、フィールドが抽象的な型の場合はunpackされませんね。例えば、標準ライブラリーの Complex a!a :+ !a みたいに定義されていますが、これもunpackできないため、自前で data ComplexDouble = MkComplexDouble !Double !Double というような特殊化された型を作るとunpackできて効率が良い、みたいな話があった気がします。
TestB a -> a みたいにフィールドを取り出す関数は a がどういう型であっても同じ機械語で取り扱えないといけないので、`a` によってフィールドの配置が変わってしまうと困るんですね。C++やRustのように多相を全部特殊化する方式ならunpackできるんですけど、Haskellはそういうコンパイル方式にはなっていないのです。
ありがとうございます。とても納得しました!
一旦保留で、速度が問題になったら特殊化を考えてみます!