Конструктор типа как возвращаемый тип

В Scala я могу определить алгебраический тип данных:

scala> sealed trait Maybe[A]
defined trait Maybe

scala> case class Just[A](x: A) extends Maybe[A]
defined class Just

scala> case object NothingHere extends Maybe[Nothing]
defined object NothingHere

Можно вернуть функцию f с типом возвращаемого значения Maybe[A].

scala> def f[A](x: A): Maybe[A] = Just(x)
f: [A](x: A)Maybe[A]

Однако также можно указать, что возвращается Just[A].

scala> def f[A](x: A): Just[A] = Just(x)
f: [A](x: A)Just[A]

Теперь я проделаю аналогичное упражнение на Haskell:

Prelude> data Option a = None | Some a deriving Show
Prelude> let f x = Some x :: Option Int
Prelude> f 10
Some 10

Но я не могу установить возвращаемый тип конструктора типа.

Prelude> let f x = Some x :: Some Int

<interactive>:10:21:
    Not in scope: type constructor or class `Some'
    A data constructor of that name is in scope; did you mean DataKinds?
Prelude> let f x = None :: None

Является ли простая разница в том, что Just в Scala является классом, то есть допустимым типом возвращаемого значения? Принимая во внимание, что в Haskell конструктор типа не может быть возвращаемым типом?


person Kevin Meredith    schedule 03.06.2015    source источник


Ответы (2)


Разница в том, как Scala решила реализовать ADT. Scala использует классы case, которые расширяют трейт в стиле ООП, поэтому каждый case — это отдельный тип, тогда как Haskell просто имеет несколько конструкторов для одного и того же типа. Поскольку они не являются отдельными типами, а просто отдельными функциями, вы не можете различить их на уровне типа. Существуют расширения, которые дают вам некоторую возможность различать уровни типов, но это не то же самое, что есть в Scala. И попытка подогнать систему типов Haskell к системе типов Scala, вероятно, не самая лучшая идея.

Короче говоря, Scala аппроксимирует ADT, используя форму наследования, тогда как Haskell использует только ADT.

person bheklilr    schedule 03.06.2015
comment
Существуют расширения, дающие вам аналогичные возможности, но очень важно, что в Haskell нет подклассов, так что вы точно не сможете делать то же самое. - person leftaroundabout; 03.06.2015
comment
@leftaroundabout Немного изменил формулировку, чтобы было более понятно, что я имел в виду расширения, которые позволяют различать конструкторы на уровне типа, но это не то, что есть в Scala. Думаете, теперь это проясняет? - person bheklilr; 03.06.2015

bhelkir и leftaroundabout указали, почему вы не можете сделать это именно в Haskell: нет понятия подтипов.

Но обратите внимание, что у АТД часто есть альтернативы, позволяющие добиться того же эффекта. В этом случае одним из методов-кандидатов будет использование типа Void в сочетании с Either:

import Data.Void

f :: Int -> Either Void Int
f x = Right x

Void — это тип, не имеющий определенных значений. Поэтому, если вы видите тип Either Void a, это означает, что, поскольку значения x :: Void нет, никто никогда не сможет построить какое-либо значение формы Left x :: Either Void a. (Исключением является случай, когда x является гарантированным неограниченным значением, но мы обычно игнорируем эту возможность.)

Это означает, что Either Void a всегда имеет форму Right a, поэтому, например, вы можете написать эту функцию:

-- | Extract the @a@ from @Either Void a@.
extract :: Either Void a -> a
extract (Left x) = absurd x
extract (Right a) = a

absurd x работает в основном следующим образом: поскольку x :: Void означает, что никогда не может быть значения для x, то absurd :: Void -> a, учитывая ее тип, является функцией, которую невозможно вызвать. То, как работает система типов, означает, что она может претендовать на возврат любого типа, который ожидает вызывающая сторона. См. этот вопрос для дальнейшего обсуждения (хотя, возможно, немного продвинутый).

person Luis Casillas    schedule 03.06.2015
comment
Может быть, я что-то упускаю, но почему бы просто не вернуть a напрямую? - person dfeuer; 04.06.2015
comment
Я имел в виду, что если исключить нижние части, Either Void a будет изоморфен a. Зачем идти на все эти проблемы? - person dfeuer; 05.06.2015