4

我有一个宇宙类型和一个工人类型。工人可以改变宇宙。我想要实现的是确保宇宙只能由来自该宇宙的工人修改(而不是将来或​​过去)。

我能做到的最好的是:

{-# 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函数返回Universe otherType类型检查器知道otherType的与 . 不同的地方t

谢谢你的时间。

4

1 回答 1

5

一种方法是使用存在类型:

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
于 2015-08-20T20:47:22.047 回答