Как создать ADT в Haskell? - PullRequest
       28

Как создать ADT в Haskell?

17 голосов
/ 23 марта 2019

В 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, чтобы сделать это?

1 Ответ

26 голосов
/ 23 марта 2019

В Scala ваш ADT делает A, B, C подтипами Foo.В Haskell у нас нет подтипов, поэтому A, B, C вместо этого являются конструкторами типа Foo.

Несколько возможных обходных путей:

  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 -> ... (или использовать экзистенциальные типы).

...