Я нашел действительно интересный пример в статье Scala, и мне интересно, как это можно закодировать в Haskell.
trait Status
trait Open extends Status
trait Closed extends Status
trait Door[S <: Status]
object Door {
def apply[S <: Status] = new Door[S] {}
def open[S <: Closed](d: Door[S]) = Door[Open]
def close[S <: Open](d: Door[S]) = Door[Closed]
}
val closedDoor = Door[Closed]
val openDoor = Door.open(closedDoor)
val closedAgainDoor = Door.close(openDoor)
//val closedClosedDoor = Door.close(closedDoor) // fails to compile
//val openOpenDoor = Door.open(openDoor) // fails to compile
Этот образец кодируется на уровне типа, который можно открыть только закрытым Door
, и закрыть только Door
. Моя первая попытка заключалась в простом использовании простых типов данных, но не работает должным образом:
data Status = Open | Closed deriving (Show)
data Door = Door Status deriving (Show)
open :: Door -> Door
open (Door Closed) = Door Open
close :: Door -> Door
close (Door Open) = Door Closed
main = do
let closedDoor = (Door Closed)
let openDoor = open closedDoor
let closedAgainDoor = close openDoor
let closeClosedDoor = close closedDoor
let openOpenedDoor = open openDoor
print closedAgainDoor
Это фактически компилируется (если я не пытаюсь напечатать closeClosedDoor
или openOpenedDoor
, который затем жалуется на неисчерпывающие шаблоны в функции open, что очевидно)
Итак, я пытаюсь выяснить, могут ли GADTs наши семейства типов выполнить эту задачу, но пока я не могу понять.
Любые идеи?