我正在尝试更新IO功能中的记录。我试图使用状态单子没有成功。我在某处看到一条评论,认为有可能用州政府解决类似的问题。是否可以使用State-monad来执行此操作,还是必须使用monad变压器?如果是这样的话,我将为您做一个简短的解释。
{-# LANGUAGE GADTs #-}
data CarState = CS {color :: String }
initState :: CarState
initState = CS {color = "white"}
data Car where
ChangeColor :: String -> Car
func :: Car -> CarState -> IO ()
func (ChangeColor col) cs = do
putStrLn ("car is " ++ show(color cs))
-- Change state here somehow
-- colorChange "green"
putStrLn ("car is now" ++ show(color cs))
main :: IO ()
main = func (ChangeColor "green") initState
colorChange :: String -> MyState CarState String
colorChange col = do
cs <- get
put $ cs {color = col}
return col
data MyState s a = St (s -> (a,s))
runSt :: MyState s a -> s -> (a,s)
runSt (St f) s = f s
evalSt :: MyState s a -> s -> a
evalSt act = fst . runSt act
get :: MyState s s
get = St $ \s -> (s,s)
put :: s -> MyState s ()
put s = St $ \_ -> ((),s)
instance Monad (MyState s) where
return x = St $ \s -> (x,s)
(St m) >>= k = St $ \s_1 -> let (a, s_2) = m s_1
St k_m = k a
in k_m s_2
instance Functor (MyState s) where
fmap f (St g) = St $ \s0 -> let (a, s1) = g s0
in (f a, s1)
instance Applicative (MyState s) where
pure a = St (\s -> (a,s))
(<*>) (St sa) (St sb) = St (\s0 -> let (fn, s1) = sa s0
(a, s2) = sb s1
in (fn a, s2))
在Haskell中,您永远无法通过任何机制对数据进行适当的突变。完全没有。1
[Haskell中状态更新的建模方式是通过产生一个新值,该值与旧值相同,除了“ updated”位。
例如,您要执行的操作将这样表示:
func :: Car -> CarState -> CarState
func (ChangeColor c) cs = cs { color = c }
1 好吧,从技术上讲,您有时可以,但是它仅适用于预先安排为可变的数据,并且通常很麻烦。不是编写程序的常规方法。