2017-02-09 4 views
1

Я иду через государственную монады here, и я пытаюсь выполнить:Ошибка конструктора данных при реализации государственной монады?

import Control.Monad.Reader 
import Control.Monad.Writer 
import Control.Monad.State 

type Stack = [Int] 

pop :: State Stack Int 
pop = State $ (x : xs) -> (x, xs) 

Однако я получаю следующее сообщение об ошибке:

"Data constructor not in scope: 
    State :: ([t0] -> (t0, [t0])) -> State Stack Int 
Perhaps you meant one of these: 
    ‘StateT’ (imported from Control.Monad.State), 
    variable ‘state’ (imported from Control.Monad.State)" 

я упускаю что-то основное здесь?

ответ

4

нет вы не являетесь. Учебник немного упрощает ( или, может быть, он просто устарел - я не ухожу далеко назад, чтобы узнать, какой из двух он устарел). Control.Monad.State определяет монаду трансформаторStateT. Он также экспортирует более простой синоним типа, эквивалентное тому, что учебник учит вас

type State s a = StateT s Identity a 

Однако это не означает, что конструктор не State, это StateT (и имеет обобщенную подпись). К счастью, на этот раз вам не нужно слишком беспокоиться.

  • Для построения State, вы можете использовать функцию state и делать вид, что имеет подпись state :: (s -> (a,s)) -> State s a (в действительности она имеет более общую подпись - что вы столкнетесь в сообщениях об ошибках).
  • Для деконструкции State, просто используйте runState :: State s a -> s -> (a,s) вместо соответствия шаблону.

Из примера вы дали:

import Control.Monad.Reader 
import Control.Monad.Writer 
import Control.Monad.State 

type Stack = [Int] 

pop :: State Stack Int 
pop = state $ \(x : xs) -> (x, xs) 
+1

Спасибо Алек, очень ясный - я рад, что я не буду суетливым в моей старости! –

+0

[Связанный учебник устарел, а не упрощает.] (Http://hackage.haskell.org/package/mtl-1.0/docs/Control-Monad-State.html # t: State) Было время, когда люди беспокоились о том, что трансформаторы, наложенные на «Identity», имели затраты времени исполнения по сравнению с определением соответствующей монады напрямую, и поэтому многие библиотеки (включая mtl) отправили как монаду, так и ее трансформатор. В конце концов, аргумент об удвоении кода/бремени обслуживания против этого выиграл над аргументом производительности для него. –

2

Почему вы предполагаете, что интерфейс к State a осуществляется через конструктор данных, который обертывает функцию s -> (a, s)? Это простой способ: реализовать Состояние, но вы не указали этот интерфейс. Вместо этого используйте конструкции, указанные в Control.Monad.State.

Одно простое изменение просто использовать строчными state функция предназначена для этой цели:

pop :: State Stack Int 
pop = state $ \(x : xs) -> (x, xs) 

В качестве альтернативы, вместо того чтобы работать с этой точки зрения низкого уровня государства, вы можете работать с ним, как не монады через свои put и get функции:

pop :: State Stack Int 
pop = do 
    (x : xs) <- get 
    put xs 
    return x 
+2

Она предполагает, что интерфейс 'State', потому что это то, что говорит учебник. :/«Модуль' Control.Monad.State' предоставляет новый тип, который обертывает вычисления с учетом состояния. Вот его определение: 'newtype State s a = State {runState :: s -> (a, s)}'. – Alec

+0

Интересно, будет ли синоним шаблона целесообразным, поэтому экспортировать «иллюзию» работы с более простым «состоянием» с помощью простого интерфейса. Полагаю, что, используя безопасные принуждения, он должен иметь нулевую стоимость исполнения. Это может быть распространено на большинство монадных трансформаторов, применяемых к «Identity». – chi

Смежные вопросы