在没有 DataKinds 的情况下,如何使值依赖于其他值?
How do I make values depend on other values without DataKinds?
我有一个 universe 类型和一个 worker 类型。工人可以改变宇宙。我想要实现的是确保 Universe 只能由来自该 Universe 的工人修改(不是未来或过去的工人)。
我能做到的最好的是:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
module Module(initialUniverse, doSomething, doStep) where
data Nat = Z | S Nat
data Universe (t :: Nat) = Universe {
_allWorkers :: [Worker t]
}
data Worker (t :: Nat) = Worker
initialUniverse :: Universe Z
initialUniverse = Universe [Worker]
doSomething :: Worker t -> Universe t -> Universe (S t)
doSomething = undefined
doStep :: Universe t -> Universe (S (S t))
doStep u = let w = head $ _allWorkers u
u2 = doSomething w u
w2 = head $ _allWorkers u2
u3 = doSomething w2 u2
in u3
如果我将 w2 = head $ _allWorkers u2
更改为 w2 = head $ _allWorkers u
,我会得到一个编译错误,这正是我想要的。
我不太喜欢的是现在每个宇宙都有一个版本,我必须手动增加它。这可以用另一种不需要显式版本控制的方式来完成吗?比如让 doSomething
函数 return 成为 Universe otherType
类型检查器会知道 otherType
不同于 t
.
感谢您的宝贵时间。
一种方法是使用存在类型:
data Un = forall s. Un (Universe s)
doSomething :: Worker s -> Universe s -> Un
initialUniverse :: Un
doStep :: Un -> Un
doStep (Un u) = let w = head $ _allWorkers u
u2 = doSomething w u
w2 = head $ _allWorkers u2
u3 = doSomething w2 u2
in Un u3
我有一个 universe 类型和一个 worker 类型。工人可以改变宇宙。我想要实现的是确保 Universe 只能由来自该 Universe 的工人修改(不是未来或过去的工人)。
我能做到的最好的是:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
module Module(initialUniverse, doSomething, doStep) where
data Nat = Z | S Nat
data Universe (t :: Nat) = Universe {
_allWorkers :: [Worker t]
}
data Worker (t :: Nat) = Worker
initialUniverse :: Universe Z
initialUniverse = Universe [Worker]
doSomething :: Worker t -> Universe t -> Universe (S t)
doSomething = undefined
doStep :: Universe t -> Universe (S (S t))
doStep u = let w = head $ _allWorkers u
u2 = doSomething w u
w2 = head $ _allWorkers u2
u3 = doSomething w2 u2
in u3
如果我将 w2 = head $ _allWorkers u2
更改为 w2 = head $ _allWorkers u
,我会得到一个编译错误,这正是我想要的。
我不太喜欢的是现在每个宇宙都有一个版本,我必须手动增加它。这可以用另一种不需要显式版本控制的方式来完成吗?比如让 doSomething
函数 return 成为 Universe otherType
类型检查器会知道 otherType
不同于 t
.
感谢您的宝贵时间。
一种方法是使用存在类型:
data Un = forall s. Un (Universe s)
doSomething :: Worker s -> Universe s -> Un
initialUniverse :: Un
doStep :: Un -> Un
doStep (Un u) = let w = head $ _allWorkers u
u2 = doSomething w u
w2 = head $ _allWorkers u2
u3 = doSomething w2 u2
in Un u3