#haskell #monads #state-monad
#haskell #монады #состояние-монада
Вопрос:
Это код состояния Монады, который я пытаюсь выяснить
data State a = State (Int -> (a, Int))
instance Monad State where
return x = State (c -> (x, c))
State m >>= f = State (c ->
case m c of { (a, acount) ->
case f a of State b -> b acount})
getState = State (c -> (c, c))
putState count = State (_ -> ((), count))
instance Show State where -- doesn't work
show (State a) = show a -- doesn't work
Я пытаюсь создать состояние как экземпляр Show, чтобы я мог видеть действие getState
и putState count
в командной строке ghci.
Любой учебник или ссылка на материал State Monad тоже были бы хороши.
Комментарии:
1. Если вы получаете ошибки компилятора, которые хотите решить, вы всегда должны указывать их в вопросе.
Ответ №1:
Вот Show
пример, который может помочь увидеть, что происходит:
instance Show a => Show (State a) where
show (State f) = show [show i " => " show (f i) | i <- [0..3]]
Затем вы можете сделать:
*Main> getState
["0 => (0,0)","1 => (1,1)","2 => (2,2)","3 => (3,3)"]
*Main> putState 1
["0 => ((),1)","1 => ((),1)","2 => ((),1)","3 => ((),1)"]
Ответ №2:
В Haskell классы типов классифицируют только типы одного и того же типа. Monad классифицирует типы типов * -> *
, в то время как Show классифицирует типы типов *
. Ваш тип состояния имеет вид * -> *
, поэтому с вашим экземпляром нет проблем Monad
, но есть проблема с вашим Show
экземпляром. State
называется «конструктором типов», потому что он использует тип для создания другого типа. Думайте об этом как о приложении функций на уровне типа. Поэтому вы можете применить определенный тип и создавать его экземпляры:
instance Show (State Char) where
show _ = "<< Some State >>"
Теперь, это не очень полезный экземпляр, попробуйте что-то вроде предложения Sjoerd, чтобы получить более значимый экземпляр Show. Обратите внимание, что его версия использует универсальный тип с ограничением.
instance (Show a) => Show (State a) where
-- blah blah
Универсальный тип есть a
, и ограничение есть (Show a) =>
, другими словами, a
само по себе должно быть экземпляром Show
.
Ответ №3:
Вот отличное (и лично мое любимое) объяснение монады состояний: научите вас Хаскеллу. (Также отличный ресурс для изучения Haskell в целом).
Возможно, вы заметили, что функции не являются частью Show
класса типов в Haskell. И поскольку State
это в основном просто newtype
оболочка для функций определенных типов, вы не можете создать (значимый) State
экземпляр Show
.
Вот код, использующий монаду состояния от LYAH:
import Control.Monad.State -- first, import the state monad
pop :: State Stack Int
pop = State $ (x:xs) -> (x,xs)
push :: Int -> State Stack ()
push a = State $ xs -> ((),a:xs)
stackManip :: State Stack Int
stackManip = do
push 3
a <- pop
pop
И вот этот код в действии из ghci
:
*Main> runState stackManip [1,2,3]
(1,[2,3])
Результатом является кортеж fst
, а кортежем является snd
(измененное) состояние.
Комментарии:
1. Есть ли какой-нибудь визуальный способ показать, как
getState
putState
работает и в приведенном выше коде?2. @Qin — я не уверен, о чем вы спрашиваете, но, возможно, вы ищете
runState
. Я добавил пример.3. ввод runState говорит
Not in scope: 'runState'
, нужно ли импортировать какой-либо модуль?