如何解压缩haskell存在类型?

时间:2010-02-19 23:18:01

标签: haskell types

尝试存在类型。似乎是获得某种类型灵活性的好方法。

在我把它包起来后,我遇到了一个解除存储类型的问题。我的代码如下:

{-# 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的类型。如何拆箱/解包存在类型?

3 个答案:

答案 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]的确切内部类型。