如何在Haskell中创建ADT?

问题描述 投票:16回答:1

在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个回答
26
投票

在Scala中,你的ADT使ABC成为Foo的亚型。在Haskell中我们没有子类型,所以ABCFoo类型的构造函数。

一些可能的解决方法:

  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 这里,在最后一行,我们可以使用类型A来引用“使用Foo 'AT构造的值”,因为标签AT仅由构造函数A使用。请注意,这种方法为Foo添加了一个标记参数,因此它略微改变了界面:我们不能再编写bar :: Foo -> ...,但我们必须编写bar :: Foo t -> ...(或使用存在类型)。
© www.soinside.com 2019 - 2024. All rights reserved.