Haskell Изменение состояния в функции ввода-вывода - PullRequest
3 голосов
/ 03 февраля 2020

Я пытаюсь обновить запись в IO-функции. Я пытался использовать государственную монаду без успеха. Я где-то видел комментарий о том, что подобную проблему можно решить с помощью государственной монады. Можно ли использовать State-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))

1 Ответ

1 голос
/ 03 февраля 2020

В Haskell вы не можете изменять данные на месте, когда-либо, с помощью любого механизма. Вообще. 1

Способ обновления состояния моделируется в Haskell путем создания нового значения, которое идентично старому значению, за исключением «обновленного» бита.

Например, то, что вы пытаетесь сделать, будет выражаться так:

func :: Car -> CarState -> CarState
func (ChangeColor c) cs = cs { color = c }

1 Ну, хорошо, технически вы можете иногда, но это работает только для данных, которые были заранее организованы, чтобы быть изменяемыми, и это обычно довольно громоздко. Не обычный способ написания программ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...