尝试存在类型。似乎是获得某种类型灵活性的好方法。
在我把它包起来后,我遇到了一个解除存储类型的问题。我的代码如下:
{-# LANGUAGE ExistentialQuantification #-}
class Eq a => Blurb a
data BlurbBox = forall a . Blurb a => BlurbBox a
data Greek = Alpha | Beta deriving Eq
instance Blurb Greek
data English = Ay | Bee deriving Eq
instance Blurb English
box1 :: BlurbBox
box1 = BlurbBox Alpha
box2 :: BlurbBox
box2 = BlurbBox Ay
main = do
case box1 of
BlurbBox Alpha -> putStrLn "Alpha"
BlurbBox Beta -> putStrLn "Beta"
BlurbBox Ay -> putStrLn "Ay"
BlurbBox Bee -> putStrLn "Bee"
此代码编译为main,然后抱怨BlurbBox Alpha的类型。如何拆箱/解包存在类型?
答案 0 :(得分:16)
实际上,存在类型无法解包,因为它们的全部意义在于,期望存在类型的代码必须以完全相同的方式(在参数多态性的意义上)工作,而不管存在类型变量的确切类型。实例
你可以通过理解
来更好地理解data BlurbBox = forall a . Blurb a => BlurbBox a
被翻译为
type BlurbBox = forall b . (forall a . Blurb a => a -> b) -> b
也就是说,BlurbBox是一种可以用于绝对所有Blurbs的多态函数,可用于产生将该函数应用于某些(未知)模糊的结果。
因此,类似于你不能写一个类型为f :: a - >的函数。 Int并且有f String = 5和f Bool = 3,你不能在BlurbBox中调用'a'的类型。
您可以查看TAPL关于存在类型的章节。它描述了我提供的翻译。
答案 1 :(得分:11)
隐藏它后,你不能*专门化一种类型。如果您需要这样的操作,请向Blurb
添加一些约束或方法。
-- choose one
class (Eq a, Show a) => Blurb a where
printBlurb :: a -> IO ()
instance Blurb Greek where
printBlurb Alpha = putStrLn "Alpha"
...
class (Eq a, Show a) => Blurb a
data Greek deriving (Eq, Show)
...
data BlurbBox = forall a. (Blurb a, Show a) => BlurbBox a
data Greek deriving (Eq, Show)
...
*我非常推荐反对这个,但如果你真的想......
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Dynamic
data Greek = Alpha | Beta deriving (Eq, Typeable)
data English = Ay | Bee deriving (Eq, Typeable)
box1 :: Dynamic
box1 = toDyn Alpha
box2 :: Dynamic
box2 = toDyn Ay
main = do
case fromDynamic box1 of
Just Alpha -> putStrLn "Alpha"
Just Beta -> putStrLn "Beta"
Nothing -> case fromDynamic box1 of
Just Ay -> putStrLn "Ay"
Just Bee -> putStrLn "Bee"
答案 2 :(得分:4)
据我所知你不能这样做。存在类型的重点是隐藏类型,因此您可以统一访问所有“实例”(有点像Java和其他面向对象语言中的子类方法的动态调度)。
因此,在您的示例中,您的“界面”为BlurbBox
,您可以使用它将某些方法统一应用于不同的BlurbBox,而不必担心内部类型a
是什么(例如,如果{ {1}}子类Blurb
,然后您可以拥有Show
并打印列表中的每个元素,而无需知道列表中每个[BlurbBox]
的确切内部类型。