【发布时间】:2011-02-12 21:44:16
【问题描述】:
我试图在 Haskell 中实现一个状态机。简化版如下:
在任何状态下,你都可以给机器一个整数,然后你得到一个整数。在状态 A 中,机器将其输入加倍。在状态 B 中,机器只是将您的输入返回给您。每当您在任一状态中看到零时,请更改为另一种状态。否则,状态不会改变。
这是我的方法:让每个状态都是一个函数,该函数既返回其输出,又返回与另一个状态对应的函数。
module Main where
a x | x == 0 = (0,b)
a x = (2*x, a)
b x | x == 0 = (0,a)
b x = (x, b)
evalstate s [] = []
evalstate s (x:xs) = (v:evalstate s' xs)
where (v,s') = s x
main :: IO ()
main = putStrLn $ show $ evalstate a [1,1,2,3,4,0,2,3,3]
不幸的是,a 和 b 的类型是无限的,GHC 抱怨:
Occurs check: cannot construct the infinite type: t = t1 -> (t2, t)
在 Haskell 中如何表达这种模式?
我当然可以这样做:
s 'a' x | x == 0 = (0,'b')
状态使用字符代码,但函数模式看起来更优雅。
【问题讨论】:
-
读者的任务:让这种模式更普遍,并为它创建一个单子接口。
-
在风格上:如果你说
a 0 = (0,b)而不是a x | x == 0 = (0,b),通常会更清楚。 -
我建议使用数据类型而不是字符代码,例如
data State = A | B。但第一个也不错。 -
深思熟虑:尝试为
a编写类型签名。有点像Int -> (Int, f),但这太模糊了。f是什么?它与a的类型相同。所以整个事情现在是Int -> (Int, (Int -> (Int, Int f)))等一下......
标签: haskell