Как реализовать класс MonadState без использования синтаксиса записи?

Мне трудно понять MonadState .

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

Итак, я попытался реализовать MonadState без использования синтаксиса записи.

Следующий код, который я написал, прошел компилятор, но мне он кажется полной ерундой.

Что не так с этим кодом?

Есть ли простой пример реализации MonadState без использования синтаксиса записи?

data Foo a b = Foo (Maybe ([a],b)) deriving (Show)

unwrapFoo :: Foo a b -> Maybe ([a],b)
unwrapFoo (Foo x) = x

instance Monad (Foo [a]) where
  return x = Foo $ Just ([], x) 
  m >>= f  = case unwrapFoo m of
               Just (_, r) -> f r
               Nothing     -> Foo Nothing 

instance MonadState Int (Foo [a]) where
  get   = Foo $ Just ([], 1)     
  put _ = Foo $ Just ([],())


*Main> get :: Foo [a] Int
Foo (Just ([],1))
*Main> put 3 :: Foo [a] ()
Foo (Just ([],()))
*Main>

person Znatz    schedule 13.05.2013    source источник
comment
Что не так, так это то, что у вас здесь нет типа данных с полным состоянием, поэтому вы не можете реализовать осмысленный экземпляр MonadState. Нет смысла изучать, как реализовать только какой-то экземпляр для определенного класса, вам скорее нужно разработать тип данных, соответствующий требованиям различных классов. Или вы разрабатываете тип данных для какой-то задачи и вдруг замечаете, что эта штука ведет себя очень похоже на монаду State. Возможно, это должен быть экземпляр MonadState? – Обычно для Monad* классов это делать не нужно, просто используйте подходящий стек трансформатора.   -  person leftaroundabout    schedule 13.05.2013
comment
Начните с newtype Foo s a = Foo (s -> (s, a)).   -  person dave4420    schedule 13.05.2013


Ответы (1)


Итак, давайте начнем с основной идеи Государственной Монады.

newtype MyState s a = MyState (s {- current state -}
                           -> (s {- New state -}, a {- New value -}))

unwrap (MyState f) = f

Итак, теперь нам нужно реализовать >>= и return.

return довольно просто:

return a = MyState $ \s -> -- Get the new state
                     (s, a) -- and pack it into our value

Другими словами, это просто передает текущее состояние с новым значением.

А теперь >>=

(MyState f) >>= g = MyState $ \state -> 
    let (newState, val) = f state
        MyState newF    = g val
    in newF state

Таким образом, мы получаем новое состояние, передаем его в нашу существующую монаду состояния, затем передаем полученную пару значение/состояние в g и возвращаем результат этого.

Общее количество различий между этим синтаксисом и записью состоит только в том, что мне пришлось вручную определить unwrap.

Чтобы завершить нашу монаду

runState = unwrap

get = MyState \s -> (s, s)
put a = MyState \s -> (a, ())
person Daniel Gratzer    schedule 13.05.2013
comment
Я видел почти все примеры реализации MonadState с типом данных, который на самом деле является оболочкой функции типа (s -> (s, a)). Можно ли избавиться от внутренней функции? - person Znatz; 14.05.2013
comment
Не совсем, это в значительной степени то, чем является монада состояния. - person Daniel Gratzer; 14.05.2013
comment
@jozefg Я думаю, что это должно было быть: in newF newState вместо in newF state в вашем определении привязки - person pkaleta; 09.09.2014