State monad在具有可变(本地)变量(如Scala)的语言中是否需要/有用?

jhe*_*dus 3 haskell scala state-monad

据我所知,在Haskell中,State monad很有用,因为没有可变变量(除非我们在IO monad中).

但是,与Scala有什么关系?State Monad是否适用于存在可变变量的语言?

在某种意义上,State Monad允许的是在Monad上下文中使用一些局部可变变量.例如这里:

 newtype Labeled anytype = Labeled (S -> (S, anytype))

 instance Monad Labeled where

   return contents = Labeled (\st -> (st, contents))

   Labeled fst0 >>= fany1 = 
     Labeled $ \st0 -> 
       let (st1, any1) = fst0 st0 
           Labeled fst1 = fany1 any1
       in fst1 st1 

 mlabel :: Tr anytype -> Lt anytype
 mlabel tr = let Labeled mt = mkm tr
             in snd (mt 0) 

 mkm :: Tr anytype -> Labeled (Lt anytype)

 mkm (Lf x)
   = updateState >>= \n -> return $ Lf (n,x)

 mkm (Br l r)
   = mkm l >>= \l' ->
     mkm r >>= \r' ->
     return $ (Br l' r')

 updateState :: Labeled S
 updateState =  Labeled (\n -> ((n+1),n))

 main = print $ mlabel tr1
Run Code Online (Sandbox Code Playgroud)

在Scala中使用可变变量,这段代码会更简单(3-4行).就像是: case class Tr (...)

case class LTr (...)

def labelTree = (... recursive call ... )

哪里labelTree使用本地可变变量来存储标签的当前状态.

我真的没有看到State Monads在Scala中的用处.为什么有人会在Scala中使用State Monad?它有什么好的用例吗?

我可以想象唯一的用例如果有状态计算是复杂的并且由几个State Monads组成,但是在那一点上我不确定使用State Monad与普通的旧函数式编程和显式参数传递相比是多么有用(相反隐式参数传递,这是状态Monad是什么).

dan*_*iaz 5

在Haskell中编写有状态操作时,有一种习惯用法,即动作只需要知道完成任务所需的最小状态,然后每个动作都会缩放为复合"全局状态".例如:

import Control.Lens
import Control.Monad.Trans.State

succInt :: StateT Int IO String
succInt = do
    modify succ
    return "Incr an Int!"

succChar :: StateT Char IO String
succChar = do
    modify succ
    return "Incr a Char!"

type GlobalState = (Char,[Int])

composite :: StateT GlobalState IO (String,String)
composite = do
    r1 <- zoom _1 succChar
    r2 <- zoom (_2.traversed) succInt
    return (r1,r2)
Run Code Online (Sandbox Code Playgroud)

如果我们执行这样的示例:

ghci> runStateT composite ('a',[1,5,7])
Run Code Online (Sandbox Code Playgroud)

结果是

(("Incr a Char!","Incr an Int!Incr an Int!Incr an Int!"),('b',[2,6,8]))
Run Code Online (Sandbox Code Playgroud)

我认为通过可变变量将状态"缩放"到更大的状态将更难实现.