Почему бы просто
module Main where
import Data.Bool
appFunc :: Integer -> Integer -> Bool -> Maybe (Integer, Integer)
appFunc i1 i2 what = bool Nothing (Just (i1,i2)) what
result = do
i1 <- Just 1
i2 <- Just 2
test <- Just True
appFunc i1 i2 test
result2 = Just 1 >>= \i1 -> Just 2 >>= \i2 -> Just True >>= appFunc i1 i2
main = do
print result
print result2
Ваш appFunc
больше похож на типичный monadFunc
.Как уже упоминалось, использование join
- это просто монадное решение, я просто перефразировал его в более идиоматический стиль.
Чтобы лучше понять эти вещи, давайте посмотрим на сигнатуру центральной аппликативной операции.
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
Все три параметра для (<*>)
являются аппликативно упакованными значениями, и (<*>)
знает "обтекание", прежде чем оно должно достигнуть пика, чтобы что-то с ними сделать.Например,
Just (+1) <*> Just 5
здесь, вычисление, включающее «обернутую» функцию (+1)
и «обернутое» значение 5
, не может изменить «обтекание» Just
в этом случае.
Ваш appFunc
, с другой стороны, нуждается в чистых значениях, чтобы произвести что-то в «обертке».Это не аппликативно.Здесь нужно сделать некоторые вычисления со значениями, чтобы узнать, какой составной частью будет «обтекание».
Давайте посмотрим на центральную монадическую операцию:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
Здесьвторой параметр делает именно это.Это функция, принимающая чистое значение и возвращающая что-то в обертке.Так же, как appFunc i1 i2
.