Как на самом деле «получить» / получить / исходное состояние в Haskell?

StackOverflow https://stackoverflow.com/questions/1036957

  •  10-07-2019
  •  | 
  •  

Вопрос

У меня есть функция:

test :: String -> State String String
test x = 
    get >>= \test ->
    let test' = x ++ test in
    put test' >>
    get >>= \test2 -> put (test2 ++ x) >>
    return "test"

Я вполне понимаю, что происходит в этой функции, и начинаю разбираться в монадах.Чего я не понимаю, так это как, когда я запускаю это:

runState (test "testy") "testtest"

функция «get» в «test» каким-то образом получает начальное состояние «testtest».Может ли кто-нибудь разобрать это и объяснить мне?

Я ценю любые ответы!

Это было полезно?

Решение

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

Строго говоря, get не " берет " Аргумент. Я думаю, что многое из того, что происходит, маскируется тем, что вы не видите - определениями экземпляров Государственной монады.

get на самом деле является методом класса MonadState. Монада State является экземпляром MonadState, обеспечивающим следующее определение get :

get = State $ \s -> (s,s)

Другими словами, get просто возвращает очень простую монаду State (помня, что монаду можно рассматривать как «оболочку» для вычисления), где любой входной s в вычислении вернет пару s в качестве результата.

Следующее, что нам нужно рассмотреть, это > > = , которое State определяет следующим образом:

m >>= k  = State $ \s -> let
    (a, s') = runState m s
    in runState (k a) s'

Итак, > > = приведет к новому вычислению, которое не будет вычислено, пока не получит начальное состояние (это верно для всех вычислений состояний, когда они находятся в их «завернутая» форма). Результат этого нового вычисления достигается путем применения того, что находится справа от > > = , к результату выполнения вычисления, которое было слева. (Это довольно запутанное предложение, которое может потребовать дополнительного чтения или двух.)

Я нашел это весьма полезным для "desugar" все, что происходит Это займет намного больше времени, но ответ на ваш вопрос (откуда берется get ) должен быть очень ясным. Обратите внимание, что следующее должно рассматриваться как psuedocode ...

test x =
    State $ \s -> let
        (a,s') = runState (State (\s -> (s,s))) s  --substituting above defn. of 'get'
        in runState (rightSide a) s'
        where 
          rightSide test = 
            let test' = x ++ test in
            State $ \s2 -> let
            (a2, s2') = runState (State $ \_ -> ((), test')) s2  -- defn. of 'put'
            in runState (rightSide2 a2) s2'
          rightSide2 _ =
            -- etc...

Это должно сделать очевидным, что конечный результат нашей функции - это новое вычисление State, которому потребуется начальное значение ( s ), чтобы остальная часть вещи произошла. Вы указали s как " testtest " с вашим вызовом runState . Если вы замените " testtest " для s в приведенном выше псевдокоде вы увидите, что в первую очередь мы запускаем get с " testtest " как «начальное состояние». В результате получается (" testtest " ;, " testtest ") и т. Д.

Итак, вот где get получает ваше начальное состояние " testtest " ;. Надеюсь, это поможет!

Другие советы

Возможно, это поможет вам глубже взглянуть на то, что State конструктор типа на самом деле есть, и как runState его использует.В GHCi:

Prelude Control.Monad.State> :i State
newtype State s a = State {runState :: s -> (a, s)}
Prelude Control.Monad.State> :t runState
runState :: State s a -> s -> (a, s)

State принимает два аргумента:тип состояния и возвращаемый тип.Он реализован как функция, принимающая начальное состояние и возвращающая возвращаемое значение и новое состояние.

runState принимает такую ​​функцию в качестве исходных входных данных и (скорее всего) просто применяет одну функцию к другой, чтобы получить пару (результат, состояние).

Твой test функция представляет собой большую композицию StateФункции типа -, каждая из которых принимает входные данные о состоянии и выдает выходные данные (результат, состояние), подключаются друг к другу таким образом, чтобы это имело смысл для вашей программы.Все runState делает, это предоставляет им отправную точку состояния.

В данном контексте, get — это просто функция, которая принимает состояние в качестве входных данных и возвращает выходные данные (результат, состояние), так что результат является входным состоянием, а состояние остается неизменным (выходное состояние является входным состоянием).Другими словами, get s = (s, s)

Переход к главе 8 («Функциональные парсеры») из Грэма Хаттона. Программирование на Haskell несколько раз, пока я правильно не понял это, а затем пошло по учебнику All About Monads , сделал это для меня.

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

Богоявление пришло, когда я рассматривал структуры управления в C ( for и while и т. д.), и я понял, что наиболее распространенной структурой управления на сегодняшний день является просто ставить одно утверждение перед другим. Прошел год изучения Хаскелла, прежде чем я понял, что это даже контрольная структура.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top