关于applicative和nested Maybe的问题
Question about applicative and nested Maybe
我写了这个函数:
appFunc :: Integer -> Integer -> Bool -> Maybe (Integer,Integer)
appFunc i1 i2 b = if b then Just (i1,i2) else Nothing
然后我在 GHCi 中使用它:
> appFunc <$> Just 3 <*> Nothing <*> Just True
Nothing
这很好,因为如果至少有一个参数是 Nothing
,那么整个表达式的计算结果为 Nothing
。但是,当所有参数都是 Just
时,我会得到一个嵌套的 Maybe
:
> appFunc <$> Just 3 <*> Just 1 <*> Just False
Just Nothing
理想情况下,我希望它的计算结果为普通的 Nothing
。所以我的解决方案是使用 join
:
> join $ appFunc <$> Just 3 <*> Just 1 <*> Just True
Just (3,1)
是否有更好的解决方案或更简洁的风格?我正在试验 monad >>=
函数但没有成功。例如我试着写:
> Just True >>= appFunc <$> Just 3 <*> Just 1
* Couldn't match expected type `Bool -> Maybe b'
with actual type `Maybe (Bool -> Maybe (Integer, Integer))'
* Possible cause: `(<*>)' is applied to too many arguments
In the second argument of `(>>=)', namely
`appFunc <$> Just 5 <*> Just 4'
In the expression: Just True >>= appFunc <$> Just 5 <*> Just 4
In an equation for `it':
it = Just True >>= appFunc <$> Just 5 <*> Just 4
* Relevant bindings include
it :: Maybe b (bound at <interactive>:51:1)
这个错误对我来说很有意义,因为:
appFunc <$> Just 3 <*> Just 1 :: m (a -> m b)
而>>= :: m a -> (a -> m b) -> m b
是否有 monad 解决方案,或者我应该坚持 join
的应用风格?
为什么不只是
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
。正如 duplode 已经提到的,使用 join
只是一个 monad 解决方案,我只是将其改写成更惯用的风格。
为了更好地了解这些事情,让我们看一下中央应用操作的签名
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
(<*>)
的所有三个参数都是应用包装值,并且 (<*>)
在需要达到峰值之前知道 "wrapping",以便对它们进行处理。例如
Just (+1) <*> Just 5
这里,涉及"wrapped"函数(+1)
和"wrapped"值5
的计算不能改变"wrapping"Just
在这种情况下。
另一方面,您的 appFunc
需要纯值才能在 "wrapping" 中产生某些东西。那不适用。这里我们需要对这些值进行一些计算,以了解 "wrapping" 的组成部分是什么。
让我们看一下中央monadic操作:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
这里的第二个参数就是这样做的。它是一个函数,它接受一个纯值并在包装中返回一些东西。就像 appFunc i1 i2
.
我写了这个函数:
appFunc :: Integer -> Integer -> Bool -> Maybe (Integer,Integer)
appFunc i1 i2 b = if b then Just (i1,i2) else Nothing
然后我在 GHCi 中使用它:
> appFunc <$> Just 3 <*> Nothing <*> Just True
Nothing
这很好,因为如果至少有一个参数是 Nothing
,那么整个表达式的计算结果为 Nothing
。但是,当所有参数都是 Just
时,我会得到一个嵌套的 Maybe
:
> appFunc <$> Just 3 <*> Just 1 <*> Just False
Just Nothing
理想情况下,我希望它的计算结果为普通的 Nothing
。所以我的解决方案是使用 join
:
> join $ appFunc <$> Just 3 <*> Just 1 <*> Just True
Just (3,1)
是否有更好的解决方案或更简洁的风格?我正在试验 monad >>=
函数但没有成功。例如我试着写:
> Just True >>= appFunc <$> Just 3 <*> Just 1
* Couldn't match expected type `Bool -> Maybe b'
with actual type `Maybe (Bool -> Maybe (Integer, Integer))'
* Possible cause: `(<*>)' is applied to too many arguments
In the second argument of `(>>=)', namely
`appFunc <$> Just 5 <*> Just 4'
In the expression: Just True >>= appFunc <$> Just 5 <*> Just 4
In an equation for `it':
it = Just True >>= appFunc <$> Just 5 <*> Just 4
* Relevant bindings include
it :: Maybe b (bound at <interactive>:51:1)
这个错误对我来说很有意义,因为:
appFunc <$> Just 3 <*> Just 1 :: m (a -> m b)
而>>= :: m a -> (a -> m b) -> m b
是否有 monad 解决方案,或者我应该坚持 join
的应用风格?
为什么不只是
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
。正如 duplode 已经提到的,使用 join
只是一个 monad 解决方案,我只是将其改写成更惯用的风格。
为了更好地了解这些事情,让我们看一下中央应用操作的签名
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
(<*>)
的所有三个参数都是应用包装值,并且 (<*>)
在需要达到峰值之前知道 "wrapping",以便对它们进行处理。例如
Just (+1) <*> Just 5
这里,涉及"wrapped"函数(+1)
和"wrapped"值5
的计算不能改变"wrapping"Just
在这种情况下。
另一方面,您的 appFunc
需要纯值才能在 "wrapping" 中产生某些东西。那不适用。这里我们需要对这些值进行一些计算,以了解 "wrapping" 的组成部分是什么。
让我们看一下中央monadic操作:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
这里的第二个参数就是这样做的。它是一个函数,它接受一个纯值并在包装中返回一些东西。就像 appFunc i1 i2
.