我有一个状态机模型,
newtype State (v :: * -> *) = State (M.Map (Var UUID v) DataPerItem)
deriving (Eq, Show)
然后我有一个Command gen exec [Update update]
,其中exec
返回了UUID
的列表,即类型为
exec :: action -> m [UUID]
这反过来意味着update
需要这样的类型
update :: State v -> action -> Var [UUID] v -> State V
要真正更新模型,我需要将Var [UUID] v
变成[Var UUID v]
。我一直盯着刺猬的功能已经有一段时间了,但是什么也没跳出来……还是我又一次在想这一切错了? :)
答案 0 :(得分:1)
这行不通,但是有充分的理由。
将状态机测试视为自动编写测试程序,其中每个Var a Symbolic
作为程序中的绑定。
因此,想象一下我正在使用操作create :: Size -> Buf
,put :: Buf -> Int -> IO ()
和get :: Buf -> IO Int
测试一个小的缓冲区。
我可以手动进行单元测试。
test :: TestT IO ()
test = do
buf <- create 3
put buf 5
put buf 10
put buf 20
retrieved <- get buf
retrieved === Just 5
使用适当的命令,刺猬也可以生成此准确的测试
test :: TestT IO ()
test = do
Var 1 = create 3
Var 2 = put (Var 1) 5
Var 3 = put (Var 1) 10
Var 4 = put (Var 1) 20
Var 5 = get (Var 1)
Var 5 === Just 5
因此,每次执行都被赋予一个变量名。
当您想要这样的东西时:
splitNames :: Var [UUID] v -> [Var UUID v]
您所要的本质上是执行列表中的每个返回都被赋予其自己的变量名。然后,程序的其余部分可以使用这些变量名。我认为最好的显示方式是:
test :: TestT IO ()
test = do
Var 1 = returnSomeNumberOfItems
Var 2 = Var 1 ! 0
Var 3 = Var 1 ! 1
现在,这里的问题是我们只是不知道returnSomeNumberOfItems
返回的列表有多长时间;我们还没有运行它;无法安全地执行此操作。