【问题标题】:State Monad Bind状态单子绑定
【发布时间】:2016-09-17 00:49:52
【问题描述】:

我想我了解 State Monad 的运作方式。我已经设法编写了一些使用 State Monad 的代码。

我了解 State 的 Monad 实例是如何工作的:

instance Monad (State s) where  
return x = State $ \s -> (x,s)  
(State h) >>= f = State $ \s -> let (a, newState) = h s  
                                    (State g) = f a  
                                in  g newState  

这段代码运行良好:

type PeopleStack = [String]

enterClub :: String -> State PeopleStack String
enterClub name = state $ \xs -> (name ++ " entered club", name:xs)

leaveClub :: State PeopleStack String
leaveClub = state $ \(x:xs) -> ("Someone left the club", xs)

clubAction :: State PeopleStack String
clubAction = do
  enterClub "Jose"
  enterClub "Thais"
  leaveClub
  enterClub "Manuel"

但是,当我尝试在绑定函数中编写 clubAction 时,我似乎无法正常工作。

这是我尝试过的:

let statefulComputation1 = enterClub "Jose"
statefulComputation1 :: State PeopleStack String

runState (statefulComputation1 >>= (enterClub "Manuel") >>= leaveClub) [] 

我收到此错误:

<interactive>:13:22:
Couldn't match type ‘StateT
                       PeopleStack Data.Functor.Identity.Identity String’
               with ‘String
                     -> StateT PeopleStack Data.Functor.Identity.Identity a’
Expected type: String
               -> StateT PeopleStack Data.Functor.Identity.Identity a
  Actual type: State PeopleStack String
Relevant bindings include
  it :: (a, PeopleStack) (bound at <interactive>:13:1)
In the second argument of ‘(>>=)’, namely ‘leaveClub’
In the first argument of ‘runState’, namely
  ‘(state1 >>= leaveClub)’

我的问题是如何使用 bind 将 do 表示法转换为函数。

【问题讨论】:

    标签: haskell functional-programming monads state-monad


    【解决方案1】:

    绑定运算符 (>>=) 右侧的每个项目都需要是一个 lambda....,这样就可以了

    runState (statefulComputation1 >>= \_ -> enterClub "Manuel" >>= \_ -> leaveClub) [] 
    

    或者,您可以使用简写(&gt;&gt;)

    runState (statefulComputation1 >> enterClub "Manuel" >> leaveClub) [] 
    

    【讨论】:

    • 哦,好的。因为 State Int Int 与 \s -> (Int, Int) 相同,所以我认为这是消耗有状态操作的函数。所以它必须是:( \ _ -> s -> (a,s)) 对吗?
    • 差不多,除了它不完全“相同”,它被包裹在一个新类型中。但是是的。
    【解决方案2】:

    您需要使用(&gt;&gt;) 而不是(&gt;&gt;=)

    runState (statefulComputation1 >> (enterClub "Manuel") >> leaveClub) []
    

    (enterClub "Manuel") 的类型为 State PeopleStack String,而 (&gt;&gt;=) 需要函数 String -&gt; State PeopleStack a 作为其第二个参数。由于您不使用 statefulComputation1 的结果,您可以将它们与 (&gt;&gt;) 结合使用,后者会忽略第一个状态计算的结果。

    【讨论】:

    • 好的。所以我可以使用>>然后只是部分应用(enterClub“Manuel”)?那是怎么回事?
    • @JoseMariaLanda - enterClub 只有一个参数,所以enterClub "Manuel" 不是部分应用程序。但是,是的,如果您有两个 State 值要按顺序运行,并且只需要第一个的效果,则可以使用 &gt;&gt;。如果您需要第一次的结果,请使用&gt;&gt;= 构造以下状态操作。
    猜你喜欢
    • 1970-01-01
    • 2017-02-13
    • 1970-01-01
    • 2016-02-02
    • 1970-01-01
    • 2019-06-17
    • 2019-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多