Монада состояния haskell в функции и аргументе

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

вот краткая информация:
функция foo изменяет состояние
функция bar изменяет состояние

Я хочу позвонить:

foo bar

если я вызываю только bar, состояние устанавливается на "bar"
если я вызываю foo bar, то состояние только "foo" вместо "foobar", поэтому кажется, что bar не изменил состояние, и я не понимаю почему.

Приветствуются любые разъяснения.

Вот полный код:

module Main where

import Control.Monad.State

main :: IO ()
main = do
  a <- execStateT test1 ""
  print a
  a <- execStateT test2 ""
  print a

type MyState = String
type MyStateMonadT = StateT MyState IO

test1 :: MyStateMonadT ()
test1 = do
  bar
  return ()

test2 :: MyStateMonadT ()
test2 = do
  foo bar
  return ()

data Foo = Foo
data Bar = Bar

foo :: MyStateMonadT Bar -> MyStateMonadT Foo
foo bar = do
  modify (++"foo")
  return Foo

bar :: MyStateMonadT Bar
bar = do
  modify (++"bar")
  return Bar

person agreif    schedule 19.02.2015    source источник


Ответы (1)


Проблема в том, что на самом деле вы не звоните bar внутри foo.

Вы можете сделать это, используя _ <- bar.

Это добавляет "foobar" к состоянию:

foo :: MyStateMonadT Bar -> MyStateMonadT Foo
foo bar = do
  modify (++"foo")
  _ <- bar
  return Foo

и это добавляет "barfoo":

foo :: MyStateMonadT Bar -> MyStateMonadT Foo
foo bar = do
  _ <- bar
  modify (++"foo")
  return Foo
person Dogbert    schedule 19.02.2015
comment
это оптимизация в компиляторе GHC? - person agreif; 19.02.2015
comment
@agreif нет. Автоматический вызов bar был бы неправильным. На самом деле это функция, которая принимает состояние и возвращает новое состояние + значение (которое в данном случае равно Bar, и мы отбрасываем его, сохраняя в _). Если вы продублируете строку _ <- bar, вы увидите, что она добавляет "bar" столько раз. - person Dogbert; 19.02.2015
comment
@agreif Нет, просто ленивая оценка. Аргументы функций никогда не оцениваются автоматически. Вот почему, например, const "foo" undefined не выдает ошибку времени выполнения. - person Rein Henrichs; 19.02.2015
comment
@ReinHenrichs Даже не ленивая оценка. Полная оценка bar не приведет к его запуску; foo должен сказать, как эффекты bar включаются в эффекты foo (в основном, где появляется строка ... <- bar). В версии OP foo указано, что эффекты bar вообще не должны включаться (не включая привязку с bar), поэтому эти эффекты не возникают. Ленивая оценка должна давать тот же результат, что и строгая оценка, если обе завершаются, поэтому она никогда не является объяснением изменения поведения. - person Ben; 20.02.2015