如何在保留类型类成员资格的同时将值包装在新的数据类型中?

时间:2014-08-01 15:30:49

标签: haskell

我是Haskell初学者在Haskell中为一些简单的语言编写玩具编译器,并且在完成解析器之后,我开始研究第一个“阶段”(类型检查,一些简化,代码生成等)。我的AST数据类型如下所示:

data Ast a = ConstInt Int a | Variable String a | SomeComplexThing .... a

关键是,我希望在每次传递后使用a槽来存储信息:比如,在解析之后我们有Ast Position,然后在类型检查之后我们有Ast (Position,TypeInfo)等等等等。

但是,我希望在舞台上独立访问此有效负载中的值。截至目前,在不同阶段,元组属于不同类型,因此没有统一的自动方式来实现这一点。如果我要移除一个舞台,一切都要改变。

所以,我心中的haskell noob想到了:Typeclasses!

现在,我可以轻松制作TypeInfoHolder类型类和PositionHolder类型类,依此类推

class TypeInfoHolder a where
  getTypeInfo::a->TypeInfo

并有一个

  data TypeInfoHolderObj a = TypeInfoHolderObj a TypeInfo

并将其设为TypeInfoHolder的实例。

现在我想以某种方式自动确保每个TypeInfoHolderObj a也是a所属的所有类的实例,也就是每个类型A a的实例。 } implements,然后TypeInfoHolderObj a也通过将类的函数应用于a

TypeInfoHolderObj成员来实现

我只是想出于好奇而知道这件事:看起来这种事情经常会出现。

1 个答案:

答案 0 :(得分:6)

你似乎有两个问题。

  1. 使用类型类提供从多个其他类型中投射某种类型的能力是一个好主意吗?和,

  2. 有没有办法让像TypeInfoHolderObj a这样的类型继承a的所有实例

  3. 对(1)的回答有点争议,因为"对"对类型类的使用有点争议。就个人而言,我认为答案是"是的"它在镜头文献中有所支持,其中像HasX这样的类词组很常见。这绝对是一个风格问题,所以很难得到一个有意义的答案 - 特别是Stack Overflow。

    (2)的答案是" no"并且很容易说明原因。仅考虑需要自动派生的许多示例实例中的一个

    instance Monoid a => Monoid (TypeInfoHolderObj a) where ...
    

    对于某些类型(可能是newtypes的类型),此实例派生可以自动完成(请参阅GeneralizedNewtypeDeriving),但对于TypeInfoHolderObj,除非TypeInfo < em>还共享Monoid实例。如果确实如此,我们可以做到

      mempty = TypeInfoHolderObj mempty mempty
      mappend (TypeInfoHolderObj a b) (TypeInfoHolderObj c d) = 
        TypeInfoHolderObj (mappend a c) (mappend b d)
    

    一般而言,我们并不了解自动派生此类实例所需的所有假设。但是,可以猜测它们何时可能发生,因为您可以期望它们在您的实例看起来有点像

    时工作
    class Foo a where ...
    instance (Foo a, Foo b) => Foo (a, b) where ...
    

    因为,实际上,TypeInfoHolderObj a只不过是(a, TypeInfo)