在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:
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扩展来做到这一点吗?
A
、B
和C
成为Foo
的子类型。在Haskell中,我们没有子类型,因此A
、B
和C
代替成为Foo
类型的构造函数。Repeat the fields. This is the most basic option.
data Foo = A Int | B String | C Int String
Define additional types, so that we can reuse them more than once.
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
Exploit a 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
Here, in the last line we are able to refer to "the values constructed using A
" using the type Foo 'AT
, since tag AT
is only used by constructor A
.
Note that this approach adds a tag parameter to Foo
, so it slightly changes the interface: we can no longer write bar :: Foo -> ...
, but we have to write bar :: Foo t -> ...
(or to use existential types).
DataKinds
、GADTs
和KindSignatures
扩展。) - chepner