runSTにおける関数合成の失敗—Higher Rank Typesにおける型推論の落とし穴
余談
2つの事柄を題に要約する言い回しとして「あるいは」以外を見つけないとブログの題があるいはだらけになってしまう…
本題
GHC「なんで私が怒ってるか分かる?runSTにST s (...)が来てるの、本当はm0 (...)が来て欲しいの」
— じょんどろ (@_Nnwww) 2017年6月21日
ぼく「は????????」 pic.twitter.com/WbiIKHzmJw
runSTの関数合成で失敗するやつ https://t.co/oyhCx80UMD
— ruichi (@ruicc) 2017年6月22日
より高ランクな型を低いランクの型パラメータで表すことはできない。
従って通常のランク1であるような関数somethingについて、something . runST
のような関数合成は上記ツイートのようなエラーを起こす。
しかしそのままだとrunST $ do
が使えず非常に不便であるため、GHC7から$について推論する特殊ルールが追加されている。
これもまたHaskellに数多ある知っていれば当然であるが、知らねば型エラーから類推するのは難しい一例と言える。 まぁともあれ、ランク2の型はSTのスコープ制限は勿論のこと、 AllowAmbiguousTypes拡張と組み合わせてfromIntegralした数値を使い回すのに非常に便利だったりする(申し訳程度の擁護)。
関数適用演算子$は空気の如く重要であるため、色々特別扱いを受けている。 例えばLevity Polymorphismが知られている。 Levity Polymorphismはhaskellの意味論でいうボトムに持ちあげられている型(Lifted)と持ちあげられていない型(UnLifted)の間で多相性を行う実装だ。 意味論についてはここで概観が読める。
Haskell/Denotational semantics - Wikibooks, open books for an open world 詳細と論文へのリンクはこちらを参照されたし。 stackoverflow.com