(以下では、 と を単純化ShowしReadます。
class Show a where show :: a -> String
class Read a where read :: String -> a
readそして、決して失敗しないと仮定してください。)
フォームの存在型を作成できることはよく知られています
data ShowVal where
ShowVal :: forall a. Show a => a -> ShowVal
そして、次の:: [ShowVal]ような「異種リスト」を作成します
l = [ShowVal 4, ShowVal 'Q', ShowVal True]
これは比較的役に立たないこともよく知られています:: [String].
l = [show 4, show 'Q', show True]
これはまさに同形です (結局のところ、a でできること
ShowValはshowそれだけです)。
リスト内の各値に対して、 の結果がshow自動的にメモ化されるため、遅延性が特に優れています。したがって、 noStringは複数回計算されます (String使用されていない s はまったく計算されません)。
Aは、関数が辞書でShowValある存在タプルと同等です。exists a. (a -> String, a)Show
についても同様の構成を作成できますRead。
data ReadVal where
ReadVal :: (forall a. Read a => a) -> ReadVal
readは戻り値がポリモーフィックであるため、存在的ではなく普遍的であることに注意してくださいReadVal(つまり、Haskell にはファーストクラスの普遍性があるため、実際にはまったく必要ないということです。ただし、ここではそれを使用して、Show)。
リストを作成することもできます:: [ReadVal]:
l = [ReadVal (read "4"), ReadVal (read "'Q'"), ReadVal (read "True")]
と同様にShow、リストは次のよう:: [ReadVal]にリストに同形です。:: [String]
l = ["4", "'Q'", "True"]
(いつでもオリジナルStringを取り戻すことができます
newtype Foo = Foo String
instance Read Foo where read = Foo
Read型クラスが開いているためです。)
Aはユニバーサル関数
(CPS スタイルの表現)ReadValと同等です。forall a. (String -> a) -> aここでは、戻り値は引数ではなく多態的であるため、ReadディクショナリはReadValプロデューサーではなくユーザーによって提供されます。
Stringただし、これらの表現のどちらでも、 を使用した表現で得られる自動メモ化は得られませんShow。私たちの型は高価な操作なので、同じ型に対して同じものを複数回read計算したくないとしましょう
。String
閉じた型があれば、次のようなことができます。
data ReadVal = ReadVal { asInt :: Int, asChar :: Char, asBool :: Bool }
そして、値を使用します
ReadVal { asInt = read s, asChar = read s, asBool = read s }
または、それらの線に沿った何か。
しかし、この場合、ReadValを 1 つの型として
のみ使用したとしてStringも、値が使用されるたびに が解析されます。多態性を保ちながらメモ化する簡単な方法はありReadValますか?
(この場合と同様に、GHC に自動的に実行させるのShowが理想的です。何らかの方法で可能であれば、より明示的なメモ化アプローチ (おそらくTypeable制約を追加することによるものでしょうか?) も問題ありません。)