在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中,你的ADT使A
,B
,C
成为Foo
的亚型。在Haskell中我们没有子类型,所以A
,B
,C
是Foo
类型的构造函数。
一些可能的解决方法:
data Foo = A Int | B String | C Int String
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
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 -> ...
(或使用存在类型)。