scala - 将 Scala 类型示例转换为 Haskell

标签 scala haskell types functional-programming

我在一篇 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

这实际上可以编译(除非我尝试打印 closeClosedDooropenOpenedDoor 然后提示函数打开中的非详尽模式,这很明显)

所以我试图弄清楚我们的类型家族的 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 用于 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

关于scala - 将 Scala 类型示例转换为 Haskell,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40939508/

相关文章:

haskell - “加入”申请?

Haskell:无法理解瓶颈

c - NSUInteger 与 NSInteger、int 与 unsigned 以及类似情况

swift - Swift is Operator 的意外结果

c# - 是否可以为 XAttribute 和 XElement 编写方法?

scala - 为什么 chisel UInt(32.W) 不能取 bit[32] 恰好为 1 的无符号数?

scala - Scala 是强类型的吗?

java - 处理一对具有严重偏斜数据的 RDD 时性能不佳

scala - Scala 对象的初始化是如何工作的?

haskell - 如何使用向量空间库(haskell)微分积分