简体   繁体   English

Haskell中的状态机模式:无限类型错误

[英]State Machine Pattern in Haskell : infinite type error

I was trying to implement a state machine in Haskell. 我试图在Haskell中实现一个状态机。 A simplified version is the following: 简化版如下:

In any state, you can feed the machine an integer and you get back an integer. 在任何状态下,您都可以为机器提供一个整数,然后返回一个整数。 In state A, the machine doubles its inputs. 在状态A中,机器将其输入加倍。 In state B, the machine just gives you back your input. 在状态B,机器只是给你你的输入。 Whenever you see a zero in either state, change to the other state. 每当您在任一状态中看到零时,请更改为其他状态。 Otherwise, the state does not change. 否则,状态不会改变。

Here's the my approach: just have each state be a function which returns both its output and the function corresponding to the other state. 这是我的方法:让每个状态成为一个函数,它返回其输出和对应于另一个状态的函数。

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]

Unfortunately, the types for a and b are infinite and GHC complains: 不幸的是, ab的类型是无限的,GHC抱怨:

Occurs check: cannot construct the infinite type: t = t1 -> (t2, t)

What is the way to express this pattern in Haskell? 在Haskell中表达这种模式的方法是什么?

I could of course do something like: 我当然可以这样做:

s 'a' x | x == 0 = (0,'b')

using character codes for the state, but the function pattern seems more elegant. 使用字符代码表示状态,但功能模式看起来更优雅。

You are trying to define a state machine with the type 您正在尝试使用该类型定义状态机

type SM = Int -> (Int, SM)

but Haskell doesn't allow this. 但是Haskell不允许这样做。 You have to use data or newtype to introduce a new named type: 您必须使用datanewtype来引入新的命名类型:

newtype SM = SM (Int -> (Int, SM))

Below is your program with this minor change applied, so that it now compiles and behaves as expected: 下面是您应用此次要更改的程序,因此它现在可以按预期编译和运行:

module Main where

newtype SM = SM (Int -> (Int, SM))

a = SM a'
    where
    a' x | x == 0 = (0, b)
    a' x = (2 * x, a)

b = SM b'
    where
    b' x | x == 0 = (0, a)
    b' x = (x, b)

evalstate s [] = []
evalstate (SM 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]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM