Is State monad needed/useful in a language with mutable (local) variables (such as Scala)?

怎甘沉沦 提交于 2021-02-07 09:10:55

问题


I understand that in Haskell the State monad is useful because there are no mutable variables (unless we are in the IO monad).

However, what is the deal with Scala ? Is State Monad useful in a language where there are mutable variables ?

In some sense all the State Monad allows is to use some local mutable variables within the Monad context. For example here:

 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

This code would be much simpler (3-4 lines) using mutable variables in Scala. Something like: case class Tr (...)

case class LTr (...)

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

where labelTree is using local mutable variables to store the current state of the label.

I don't really see the usefulness of State Monads in Scala. Why would anyone use State Monad in Scala ? Are there any good use cases for it ?

The only use case I can imagine if the stateful computation is complex and is composed from several State Monads, but at that point I am not sure how useful it is to use State Monad in contrast to plain old functional programming and explicit argument passing (instead of implicit argument passing which is what the State Monad is).


回答1:


When composing stateful actions in Haskell, there is an idiom in which actions only demand to know the bare minimum of state needed to accomplish their tasks, and then each action is zoomed into a composite "global state". For example:

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)

If we execute the example like this:

ghci> runStateT composite ('a',[1,5,7])

The result is

(("Incr a Char!","Incr an Int!Incr an Int!Incr an Int!"),('b',[2,6,8]))

I think the "zooming" of the states into bigger states would be more difficult to accomplish with mutable variables.




回答2:


The great advantage of State monad on mutable variables (that is, in a functional programming mindset) is reference transparency.

A chunk of code using the State monad is more easily unit-testable, more maintainable, and less error prone than the equivalent using vars, because the logic of the code will not depend on where and when this code is run.

Another viewpoint of the same issue is that the State monad encodes in the type system the fact that a value is mutable, while a var gives no such information.

EDIT

However, the state monad is probably always less efficient than mutable variables, because it adds another level of abstraction between the written code and the compiled output. But this can be said for most of functional constructs, so this is not a real argument for the use of vars in functional scala code.



来源:https://stackoverflow.com/questions/43230520/is-state-monad-needed-useful-in-a-language-with-mutable-local-variables-such

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!