Haskell状态monad在偶数和奇数函数调用上的行为不同

时间:2018-12-01 08:11:20

标签: haskell state-monad

我想创建一个函数,它使用状态monad在奇数调用上加5,在偶数调用上减去6。

f 5 =  10
f 7 = 1
f 4 = 9
f 2 = -4

0是偶数,所以f 5加5。 1是奇数,所以f 7减去6,依此类推。

我现在所拥有的:

data Parity = Even | Odd deriving (Show, Eq)

not' :: Parity -> Parity
not' Even = Odd
not' Odd = Even

isOdd :: Int -> State Parity Int
isOdd x = state $ \(p) -> (if p == Odd then x + 5 else x - 6, not' p)

g n = do isOdd n

apply n = runState (g n) Even

我试图这样写,但是每次使用“ apply”时都不会保存状态。 由于末尾只有偶数,所以只加5。 如何使它保存状态,并且只初始化一次而不是每次都初始化呢?

1 个答案:

答案 0 :(得分:3)

我几天前写的这篇answer可能会有所帮助。 简而言之,State s只是将“有状态功能” f :: a -> b模拟为纯功能f :: (a,s) -> (b,s)的便捷方法。为了适应monad框架,尽管它们是经过咖喱处理的,所以(大致)形式为f :: a -> s -> (b,s)

类型State s b大致为s -> (b,s),可以理解为“返回值b和最终状态s且需要初始状态的计算s待运行”。因此,单子函数a -> State s b是接受输入a的函数,可以在给定初始状态s的情况下运行,以产生值b和最终状态s

您的函数isOdd

isOdd x :: Int -> State Parity Int
isOdd x = state $ \p -> (if p == Odd then x + 5 else x - 6, not' p)

大概是

isOdd' x :: Int -> Parity -> (Int,Parity)
isOdd' x p = (if p == Odd then x + 5 else x - 6, not' p)

您的电话

 apply n = runState (isOdd n) Even 

大概是

 apply' n = isOdd' x Even

仅此而已。您实质上是在计算

 apply' n = --definition of apply'
            isOdd' n Even
            -- definition of isOdd'
            (\x p -> (if p == Odd then x + 5 else x - 6, not' p)) n Even
            -- application to the arguments `n` and `Even` 
            = (if Even == Odd then n + 5 else n - 6, not' Even)
            -- simplifying
            = (n - 6, Odd)

所以

apply' n = (n - 6, Odd)

以下是如何正确排序函数的示例,

f :: Int -> State Parity Int
f n = isOdd n >>= (\x -> isOdd x) 

或等效地

f :: Int -> State Parity Int
f n = do x <- isOdd n
         isOdd x

通过例如apply n = runState (f n) Even首先运行isOdd n Even,以获得结果m和新的最终状态False,然后运行isOdd m False