【问题标题】:How to create ADT in Haskell?如何在 Haskell 中创建 ADT?
【发布时间】:2019-08-14 04:04:40
【问题描述】:

在 Scala 中我可以描述这样的 ADT:

sealed trait Foo
case class A(a: Int) extends Foo
case class B(b: String) extends Foo
case class C(a: A, b: B) extends Foo

我怎样才能在 Haskell 中做同样的事情?

data Foo = A Int | B String | C A B

它不起作用,因为 A 和 B 不是类型。我应该使用 GHC 扩展来做到这一点吗?

【问题讨论】:

    标签: scala haskell algebraic-data-types


    【解决方案1】:

    在 Scala 中,您的 ADT 使 A,B,C 成为 Foo 的子类型。在 Haskell 中,我们没有子类型,所以 A,B,CFoo 类型的构造函数。

    一些可能的解决方法:

    1. 重复字段。这是最基本的选项。

      data Foo = A Int | B String | C Int String
      
    2. 定义其他类型,以便我们可以多次重复使用它们。

      data AT = AT Int      -- can have many arguments
      data BT = BT String   -- can have many arguments
      data Foo = A AT | B BT | C AT BT
      
    3. 利用 GADT

      data FooTag = AT | BT | CT
      
      data Foo (tag :: FooTag) where
         A :: Int -> Foo 'AT
         B :: String -> Foo 'BT
         C :: Foo 'AT -> Foo 'BT -> Foo 'CT
      

      在这里,在最后一行中,我们可以使用Foo 'AT 类型引用“使用A 构造的值”,因为标签AT 仅由构造函数A 使用。 注意,这种方式在Foo中添加了一个标签参数,所以它稍微改变了界面:我们不能再写bar :: Foo -> ...,但我们必须写bar :: Foo t -> ...(或者使用存在类型)。

    【讨论】:

    • 最后一个例子需要几个扩展,对吧? (DataKindsGADTsKindSignatures,我想。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-03
    • 2011-09-05
    • 1970-01-01
    相关资源
    最近更新 更多