Возврат значения с помощью монады состояния

Я новичок в Monads и Haskell в целом и пытаюсь понять, как вернуть значение при их использовании. Мой код выглядит примерно так:

foo :: A -> B
foo a = do  b <- fooC a (C 0)
            -- want to return just (B "b")

fooC :: A -> C -> State MyState B
fooC a c = return (B "b")

Я пытался использовать snd (snd b), но, видимо, State MyState B не является кортежем? Как вернуть нужное значение (B "b")?

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

data MyState = MyState String
data C = C Int
foo :: String -> String
-- want to return just "b"
foo a = evalState (fooC a) (C 0)

fooC :: String -> Int -> State MyState String
fooC a c = return "b"

Это по-прежнему приводит к ошибке компиляции:

Couldn't match expected type `State s0 String'
            with actual type `Int -> State MyState String'
In the return type of a call of `fooC'
Probable cause: `fooC' is applied to too few arguments
In the first argument of `evalState', namely `(fooC a)'
In the expression: evalState (fooC a) (C 0)

Изменить 2: исправлено! Окончательный вариант выглядит следующим образом:

import Control.Monad.State
data MyState = MyState String
data C = C Int
foo :: String -> String
-- want to return just (B "b")
foo a = evalState (fooC a (C 0)) (MyState "whatever")

fooC :: String -> C -> State MyState String
fooC a c = return "b"

main = print(foo("test"))
-- prints "b"

person Wesley Tansey    schedule 22.11.2012    source источник


Ответы (1)


Что вам нужно, это

foo a = evalState (fooC a (C 0)) (MyState "whatever")

Вы создаете State MyState B действие fooC a (C 0), разворачиваете его, чтобы получить функцию, и применяете эту функцию к начальному состоянию. Поскольку в этом примере состояние не используется, вы также можете использовать здесь undefined вместо MyState "whatever", но в общем случае вам необходимо указать осмысленное начальное состояние.

State MyState B не кортеж, он изоморфен функции

MyState -> (B, MyState)

но эта функция обернута в newtype (детали зависят от пакета и версии библиотеки преобразования монад), поэтому для доступа к результату этой функции, примененной к начальному состоянию, вам нужна функция разворачивания. Для State есть

runState :: State s r -> (s -> (r,s))

который дает вам функцию, возвращающую пару,

evalState :: State s r -> (s -> r)

это дает вам функцию, состоящую из fst, поэтому конечное состояние отбрасывается, и

execState :: State s r -> (s -> s)

который составляет функцию с snd, поэтому возвращается только конечное состояние.

person Daniel Fischer    schedule 22.11.2012
comment
Ой, извините, ошибка синтаксического анализа с моей стороны. Обновлено. - person Daniel Fischer; 22.11.2012