【发布时间】:2016-04-01 12:35:37
【问题描述】:
是否可以在 Haskell 中使用 GADT 而不是 Dynamic 来实现异构 Data.Map?我尝试按照this answer 中的说明对异构集合进行建模:
{-# LANGUAGE GADTs #-}
class Contract a where
toString :: a -> String
data Encapsulated where
Encapsulate :: Contract a => a -> Encapsulated
getTypedObject :: Encapsulated -> a
getTypedObject (Encapsulate x) = x
这个想法是Encapsulated 可用于存储TypeClass a 的不同对象,然后在运行时提取特定类型。
我收到关于 x 类型与 Contract a 不匹配的错误。也许我需要指定某种类约束来告诉GHC Encapsulate x 中的x 类型与Contract a 中的a 相同?
T.hs:10:34:
Couldn't match expected type ‘a’ with actual type ‘a1’
‘a1’ is a rigid type variable bound by
a pattern with constructor
Encapsulate :: forall a. Contract a => a -> Encapsulated,
in an equation for ‘getTypedObject’
at T.hs:10:17
‘a’ is a rigid type variable bound by
the type signature for getTypedObject :: Encapsulated -> a
at T.hs:9:19
Relevant bindings include
x :: a1 (bound at T.hs:10:29)
getTypedObject :: Encapsulated -> a (bound at T.hs:10:1)
In the expression: x
In an equation for ‘getTypedObject’:
getTypedObject (Encapsulate x) = x
我正在尝试这种方法,因为我有不同类型的 JSON 对象,并且根据在运行时通过网络解码的类型,我们希望从 Map 检索适当的特定类型 builder(已加载在运行时 IO 从配置文件中main,并传递给函数)并将其传递给解码的相同类型的 JSON 数据。
Dynamic 库可以在这里工作。但是,我有兴趣了解是否有其他可能的方法,例如 GADTs 或 datafamilies。
【问题讨论】:
-
也许值得注意的是,在这种情况下,您甚至不需要 GADT;让
ExistentialQuantification写data Encapsulated = forall a. Show a => Encapsulate a之类的东西就足够了 -
对于许多(大多数?)目的,几乎可以肯定的是,
Dynamic在概念上是多余的,Typeable约束就足够了。data Box where Box :: Typeable a => a -> Box。然后你可以使用从Data.Typeable到Maybe的函数来获取一个开箱即用的值。 -
在 GHC 8.2 中,
Typeable预计将变得更加强大,超过包含Dynamic当前提供的功能。