[英]Translate a Scala Type example to Haskell
我在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
,然后在功能打开时抱怨非详尽的模式,这很明显)
所以我试图弄清楚GADT我们的类型家族是否可以完成这项任务,但我还不知道如何。
有任何想法吗?
除了bheklilr的答案,你可以使用一些类型扩展来更接近Scala示例并排除非敏感类型,如
Door String
使用DataKinds
,您可以有效地禁止幻像类型只是一个Status
。
{-# LANGUAGE DataKinds #-}
data Door (status :: Status) = Door
data Status = Open | Closed
open :: Door Closed -> Door Open
open _ = Door
close :: Door Open -> Door Closed
close _ = Door
然后,对于类型系列,我们甚至可以定义“切换”门的含义
{-# LANGUAGE TypeFamilies #-}
type family Toggle (s :: Status) where
Toggle Open = Closed
Toggle Closed = Open
toggle :: Door s -> Door (Toggle s)
toggle Door = Door
作为一个结束的想法,使用GADT for Door
可能更好 - 只是因此你有两个不同的构造函数名称。 我个人认为这看起来更好
{-# LANGUAGE GADTs, DataKinds, TypeFamilies #-}
data Door (status :: Status) where
OpenDoor :: Door Open
ClosedDoor :: Door Closed
open :: Door Closed -> Door Open
open _ = OpenDoor
close :: Door Open -> Door Closed
close _ = ClosedDoor
toggle :: Door s -> Door (Toggle s)
toggle OpenDoor = ClosedDoor
toggle ClosedDoor = OpenDoor
我会做点什么的
data Open = Open deriving (Show)
data Closed = Closed deriving (Show)
data Door door_state = Door deriving (Show)
open :: Door Closed -> Door Open
open _ = Door
close :: Door Open -> Door Closed
close _ = Door
现在没有任何情况需要考虑,状态本身是在类型中编码的,就像Scala示例一样。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.