如何在Haskell中建模分层数据类型?

时间:2017-01-06 11:07:13

标签: haskell

我有一堆类型,其层次结构存储一些有用的信息。我试图避免不得不将类型层次结构的知识烘焙到对其进行操作的函数中。

以下是斯坦福大学自然语言处理的类型依赖关系摘录:

root - root
dep - dependent
  aux - auxiliary
    auxpass - passive auxiliary 
    cop - copula
  arg - argument 
    agent - agent

我想创建一些镜像此结构的数据类型,以便我可以定义一些只能在某些类型上运行的函数。当我有一个在arg上运行的函数时,我用来表示arg的类型也应包含agent,但agent的类型不应包含arg }}。 dep的类型应包含其下方的任何内容。

这是否可以在haskell?我一直在尝试声明各种data类型来对此进行建模,但由于数据类型无法使用其他数据类型的构造函数,因此我无法使其工作。

我怀疑这种方法可能与Haskell不能很好地协作,所以如果是这样的话,你通常如何处理这些平铺层次结构绝对不可取的情况呢?

2 个答案:

答案 0 :(得分:1)

一般来说,对Haskell来说,子类型不能很好地发挥作用。但是,如果您只是尝试建模(非多重)继承(因此您有一个子类型树而不是格子),您实际上可以使用类型类构建子类型。 Here is a short gist that does exactly this.从那里开始,您可以定义数据类型

data Root = Root ...
data Dep = Dependent ...
data Aux = Auxiliary ...
data AuxPass = PassiveAuxiliary ... 
data Cop = Copula ...
data Arg = Argument ...
data Agent = Agent ...

以及相应的实例

instance Subtype Aux where
  type SuperType Aux = Dep
  embedImmediate = ...

instance Subtype AuxPass where
  type SuperType AuxPass = Aux
  embedImmediate = ...

instance Subtype Cop where
  type SuperType Cop = Aux
  embedImmediate = ...

instance Subtype Arg where
  type SuperType Arg = Dep
  embedImmediate = ...

instance Subtype Agent where
  type SuperType Agent = Arg
  embedImmediate = ...

如何填写...取决于您。你可以为此做几件事:

  • 如果您的子类型在超类型之上添加了大量字段,则只需添加一个具有超类型的字段并使embedImmediate返回该字段
  • 如果您的子类型只添加了几个字段,您可能需要手动解压缩它们。您的data定义看起来更整洁,但embedImmediate定义会更长一些
  • 如果您的子类型没有向超类型添加任何字段,您只需在超级类型newtype周围embedImmediate = coerce(来自Data.Coerce

然后,您可以完全只使用期望超类型的函数中的子类型,但几乎:您只需要添加对embed的调用(与{{不同) 1}}!)从子类型转换为需要的超类型(基于类型推断)。您可以查看some example uses

请注意,您现在可以使用embedImmediate作为约束:例如<:子类型的内容类型为Aux。每当您希望将此内容视为(a <: Aux) => a(或Aux的超级类型)时,请在其上调用Aux

这种方法的一个重大缺点是输入和输出类型必须注释(否则它不是 哪个超类型你希望embed进入你&#&# 39; ll得到&#34;模糊类型&#34;错误)。如果你已经写了很多签名,你应该没事。

答案 1 :(得分:0)

使用类型类。

首先将每个具体类型定义为单独的数据声明。

然后,对于每个具有子类型的类型,声明一个在其父类型上具有约束的类型类。这种关系的一个例子是Functor =&gt; Applicative =&gt; Monad结构在前奏中。

所以定义示例结构:

class Root where
    ...

class Root => Dep where
    ...

class Dep => Aux where
    ...

class Aux => Auxpass where
    ...

class Aux => Cop where
    ...

class Dep => Arg where
    ...

class Arg => Agent where
    ...