Haskell中的异构Data.Map

时间:2016-04-01 12:35:37

标签: haskell gadt

是否可以使用Data.Map代替GADT在Haskell中执行异构Dynamic?我尝试按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 x中的Encapsulate x类型与a中的Contract 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对象,并且根据通过线路在运行时解码的类型,我们希望从{{1}检索适当的类型特定的builder (在Map中从配置文件加载到运行时IO,并传递给函数)并传递相同类型的解码JSON数据。

main库可以在这里工作。但是,我有兴趣了解是否有其他可能的方法,例如DynamicGADTs

2 个答案:

答案 0 :(得分:4)

你的问题是你再次推出tr '\001' ' ' < inputfile (这是行不通的) - 你可以做的就是在内部使用合同

a

基本上编译器会告诉你需要知道的一切:你有一个useEncapsulateContract :: Encapsulated -> String useEncapsulateContract (Encapsulate x) = toString x (所以基本上是约束forall a. Contract aa

Contract上你没有这个约束 - 你告诉编译器:&#34;看起来这适用于每个getTypedObject :: Encapsulated -> a我的需求&#34;

要实现这一目标,您必须将a参数化为Encapsulated,这显然是您不想要的。

第二个版本(我给的内部版本)有效,因为你对数据构造函数有约束,所以你可以在那里使用它

稍微扩大一点:

Encapsulated a

现在不会像getTypedObject :: Contract a => Encapsulated -> a getTypedObject (Encapsulate x) = x 那样工作,但它仍然可以是两个不同类型的,它们只是共享这个类。

并且给编译器提示两者应该是相同的,你必须再次参数化Contract a ....

现在这样做:

Encapsulate

你删除了那些信息

答案 1 :(得分:4)

@Carsten答案显然是正确的,但我的两分钱让我明白了之前。

当你写:

getTypedObject :: Encapsulated -> a

你在说什么“是”:

  

getTypedObject是一个可以取Encapsulated类型值的函数,只要任何类型,就可以使用其结果。

你显然无法满足这一点,编译器不允许你尝试。您只能使用有关Encapsulated内部值的知识,根据Contract显示有意义的内容。换句话说,如果Contract不在那里,那么你就无法用该值做任何有意义的事情。

这里的概念可以简单地描述为类型擦除,并且也存在于其他语言中,C ++是我所知道的。因此,价值在于删除有关类型的所有信息,除了您希望通过它们满足的合同保留的内容。缺点是恢复原始类型需要运行时检查。

作为奖励,以下是动态方法的工作方式:

{-# LANGUAGE GADTs #-}

import Unsafe.Coerce

data Encapsulated where
   Encapsulate :: Show a => a -> Encapsulated

getTypedObject :: Encapsulated -> a
getTypedObject (Encapsulate x) = unsafeCoerce x

printString :: String -> IO ()
printString = print

x = Encapsulate "xyz"
y = getTypedObject x

main = printString y

但很容易看出它会如何破裂,对吧? :)