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

Haskell state monad different behaviour on even and odd function calls

我想制作一个函数,使用状态 monads 在奇数调用上加 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,因为最后是偶数。 我如何让它保存状态并且只初始化一次而不是每次?

我几天前写的这篇 可能会有帮助。 简而言之,State s 只是将 "stateful functions" f :: a -> b 模拟为纯函数 f :: (a,s) -> (b,s) 的一种便捷方式。为了适应 monad 框架,尽管这些是柯里化的,所以(大致)形式为 f :: a -> s -> (b,s)

类型State s b大致是s -> (b,s),可以读作"a computation that returns a value b and a final state s and that requires an initial state s to be run"。因此,单子函数 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