Обоснование использования ››

В главе Real World Haskell они дают обоснование (>>) следующим образом:

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

Затем они приводят хороший пример, демонстрирующий это:

ghci > print "foo" >> print "bar"
"foo"
"bar"

Позже в этой главе они используют ту же концепцию для генерации случайных значений в монаде State:

getRandom :: Random a => RandomState a
getRandom =
  get >>= \gen ->
  let (val, gen') = random gen in
  put gen' >>
  return val

Но почему в этом случае они используют оператор put gen' >>, когда в конечном итоге игнорируют его выходное значение. Почему вышеуказанная функция не может быть примерно такой:

getRandom :: Random a => RandomState a
getRandom =
  get >>= \gen ->
  let (val, gen') = random gen in
  return val

Просто для завершения этого вопроса я добавляю связанные определения типов и функции для вышеуказанного контекста:

newtype State s a = State {
  runState :: s -> (a, s)
  }

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

put :: s -> State s ()
put s = State $ \_ -> ((), s)

type RandomState a = State StdGen a

person Sibi    schedule 30.11.2013    source источник
comment
в вашем блоке кода ниже, почему функция не может быть такой, куда делся put?   -  person d8d0d65b3f7cf42    schedule 30.11.2013
comment
Обратите внимание, что случайная монада также находится в выделенной библиотеке. Установка обновленных генераторов обычно выполняется автоматически, как и должно быть, но это необходимо сделать, если вы не хотите просто поток одного постоянного значения. На более высоких уровнях вы будете использовать только getRandom и вам не нужно заботиться о том, как он передается генератору. — Но, конечно, есть приложения, в которых вам действительно нужны явные побочные эффекты без полезного возвращаемого значения. Однако обычно вы будете использовать нотацию do, поэтому >> действительно не очень часто встречается.   -  person leftaroundabout    schedule 01.12.2013


Ответы (1)


Потому что put имеет побочный эффект. Он вставляет что-то в монаду состояния, к которой можно получить доступ и изменить ее позже.

Возвращаемое значение равно (), что скучно, поэтому нас это не волнует, но мы, безусловно, хотим убедиться, что новый генератор случайных чисел находится в состоянии.

Подумайте об этом так: монада состояния на самом деле является функцией s -> (a, s). и put есть

put s = \oldState -> (() , s)

Так что у этого есть побочный эффект, он отбрасывает старое состояние и заменяет его. Рассмотрим этот пример

  test = put 1 >> get >>= \x -> put 2 >> get >>= \y -> return (x, y)

  -- or with do notation
  test' = do
    put 1
    x <- get
    put 2
    y <- get
    return (x, y)

Здесь x — это 1, а y — это 2. Clearly put имеет интересные эффекты, помимо возвращаемого значения.

person Daniel Gratzer    schedule 30.11.2013
comment
Я думаю, что это должно быть так: put s = \oldState -> ((), s) - person Sibi; 30.11.2013
comment
@Sibi Да, у меня это провалилось (a, s) против (s, a). Однако точка немного ортогональна. - person Daniel Gratzer; 30.11.2013