haskell中是否有“Any”types?

说,我想定义一个logging这样的属性:

data Attribute = Attribute {name :: String, value :: Any}

这当然不是有效的haskell代码。 但有没有一种types的“任何”,基本上说任何types都可以做? 或者是使用typesvariables的唯一方法?

data Attribute a = Attribute {name :: String, value :: a}

一般来说, Anytypes都不是很有用。 考虑一下:如果你创build一个可以容纳任何东西的多态列表,你可以用列表中的types做什么? 答案当然不算什么 – 你不能保证这些元素有任何共同的操作。

通常会做的是:

  1. 使用GADT创build一个可以包含特定typestypes元素的列表,如下所示:

     data FooWrap where FooWrap :: Foo a => a -> FooWrap type FooList = [FooWrap] 

    使用这种方法,您不知道元素的具体types,但是您知道可以使用Footypes元素来操作元素。

  2. 创build一个在列表中包含的特定具体types之间切换的types:

     data FooElem = ElemFoo Foo | ElemBar Bar type FooList = [FooElem] 

    这可以与方法1相结合来创build一个列表,该列表可以包含固定的一组types的元素。

  3. 在某些情况下,build立一个操作函数列表会很有帮助:

     type FooList = [Int -> IO ()] 

    这对于事件通知系统是非常有用的。 在添加一个元素到列表中的时候,你可以将它绑定到一个函数中,该函数将执行你以后想要做的任何操作。

  4. 使用Data.Dynamic (不推荐!)作为作弊。 然而,这不能保证一个特定的元素可以被操纵,所以上述方法应该是优选的。

添加到bdonlan的答案:而不是GADT,你也可以使用存在types :

 {-# LANGUAGE ExistentialQuantification #-} class Foo a where foo :: a -> a data AnyFoo = forall a. Foo a => AnyFoo a instance Foo AnyFoo where foo (AnyFoo a) = AnyFoo $ foo a mapFoo :: [AnyFoo] -> [AnyFoo] mapFoo = map foo 

这基本上等同于bdonlan的GADT解决scheme,但并不强制您select数据结构 – 您可以使用Map而不是列表,例如:

 import qualified Data.Map as M mFoo :: M.Map String AnyFoo mFoo = M.fromList [("a", AnyFoo SomeFoo), ("b", AnyFoo SomeBar)] 

data AnyFoo = forall a. Foo a => AnyFoo a data AnyFoo = forall a. Foo a => AnyFoo a也可以用GADT表示法写成:

 data AnyFoo where AnyFoo :: Foo a => a -> AnyFoo 

Data.Dynamictypes可以容纳任何东西(好的,任何Typeable )。 但这很less是正确的做法。 你试图解决什么问题?

这听起来像是一个很基本的问题,所以我会给出一个比其他人更基本的答案。 以下几乎总是正确的解决scheme:

 data Attribute a = Attribute { name :: String, value :: a } 

然后,如果你想要一个包装一个Int的属性,那么这个属性的types应该是Attribute Int ,或者一个包装一个Bool的属性的types是Attribute Bool ,等等。你可以用任何types的值创build这些属性。 例如,我们可以写

 testAttr = Attribute { name = "this is only a test", value = Node 3 [] } 

创build一个typesAttribute (Tree Int)

如果您的数据最终需要特定types,则可以将Convertible与GADT一起使用。 因为作为消费者,你只对你需要使用的数据types感兴趣。

 {-# LANGUAGE GADTs #-} import Data.Convertible data Conv b where Conv :: a -> (a -> b) -> Conv b Chain :: Conv b -> (b -> c) -> Conv c unconv :: (Conv b) -> b unconv (Conv af) = fa unconv (Chain cf) = f $ unconv c conv :: Convertible ab => a -> Conv b conv a = (Conv a convert) totype :: Convertible bc => Conv b -> Conv c totype a = Chain a convert 

为此派生函子,共性和单子实例并不是很困难。 如果你有兴趣,我可以发表。