Снятая «если» -функция ведет себя неожиданно

в своей программе я использую функцию if', определенную в одном из модулей, вместо встроенной конструкции if-then-else. Он определяется тривиально и отлично работает.

Однако есть одно место в коде, где мне нужно применить его к значениям монад (IO в моем случае), т.е. сигнатура типа должна выглядеть примерно как IO Bool -> IO a -> IO a -> IO a. Естественно, я попробовал поднять.

if' <$> mb <*> action1 <*> action2

Но когда я пытаюсь оценить выражение, я не получаю того, чего ожидаю.

*Main> if' <$> return True <*> putStrLn "yes" <*> putStrLn "no"
yes
no

Я знаю, что <*> описание читается как «последовательное приложение», так что, может быть, дело в этом. Но что здесь происходит? Могу ли я исправить это, не написав совершенно новую специальную функцию?


person Xyzzy1201    schedule 06.03.2016    source источник
comment
В последнем выражении оператор if управляет только возвращаемым значением - обе ветви должны быть выполнены, чтобы даже вычислить эти значения, поскольку он использует прикладной интерфейс для ввода-вывода. Вы, вероятно, захотите return True >>= \b -> if' b (putStrLn "yes") (putStrLn "no") - обратите внимание, как if' применяется напрямую к разным ветвям.   -  person user2407038    schedule 06.03.2016


Ответы (1)


(<*>) оценивает оба своих аргумента, так что это фактически конвейер приложений, поднятых над некоторым аппликативом. Возможность проверять значения и изменять будущее вычислений - это дополнительная мощность, которую класс Monad имеет по сравнению с Applicative, поэтому вам нужно использовать это вместо этого, например.

mif' :: Monad m => m Bool -> m a -> m a -> m a
mif' bm xm ym = bm >>= (\b -> if b then xm else ym)
person Lee    schedule 06.03.2016
comment
У @Carl есть отличный ответ по этому поводу на https://stackoverflow.com/questions/17409260/what-advantage-does-monad-give-us-over-an-applicative - person badcook; 06.03.2016