有关适用性和嵌套Maybe的问题 [英] Question about applicative and nested Maybe

查看:89
本文介绍了有关适用性和嵌套Maybe的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了这个函数:

appFunc :: Integer -> Integer -> Bool -> Maybe (Integer,Integer)
appFunc i1 i2 b = if b then Just (i1,i2) else Nothing

然后我在GHCi中这样使用它:

And then I use it as such in GHCi:

> appFunc <$> Just 3 <*> Nothing <*> Just True
Nothing

这很棒,因为如果至少一个参数为Nothing,则整个表达式的计算结果为Nothing.但是,当所有参数都是Just时,我得到一个嵌套的Maybe:

Which is great because if at least one of the parameters is Nothing then the whole expression evaluates to Nothing. However, when all parameters are Just then I get a nested Maybe:

> appFunc <$> Just 3 <*> Just 1 <*> Just False
Just Nothing

理想情况下,我希望它评估为普通的Nothing.所以我的解决方案是使用join:

Ideally, I would like it to evaluate to plain old Nothing. So my solution was to use join:

> join $ appFunc <$> Just 3 <*> Just 1 <*> Just True
Just (3,1) 

是否有更好的解决方案或更简洁的风格?我正在尝试monad >>=函数,但没有成功.例如,我尝试编写:

Is there a better solution or cleaner style? I was experimenting with the monad >>= function but with no success. For example I tried writing:

> 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)

这个错误对我来说很有意义,因为:

This error makes sense to me because:

 appFunc <$> Just 3 <*> Just 1 :: m (a -> m b) 

>>= :: m a -> (a -> m b) -> m b

是否有monad解决方案,还是应该使用join坚持应用风格?

Is there a monad solution or should I just stick to the applicative style with 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解决方案,我只是将其改写为更惯用的样式.

Your appFunc is more like a typical monadFunc. As duplode already mentioned, using join is just a monad solution, I just rephrased that into the more idiomatic style.

为了更好地了解这些内容,让我们看一下中央应用操作的签名

To get a better intuition of those things, let's look at the signature of the central applicative operation

(<*>) :: Applicative f => f (a -> b) -> f a -> f b

(<*>)的所有三个参数都是应用包装的值,并且(<*>)在需要对之进行处理之前就知道了包装".例如

All three parameters to (<*>) are applicatively wrapped values and (<*>) knows the "wrapping" before it needs to peak into it, to do something with them. For example

Just (+1) <*> Just 5

在这种情况下,涉及包装"函数(+1)和包装"值5的计算在这种情况下不能更改包装" Just.

here, the calculation involving the "wrapped" function (+1) and the "wrapped" value 5 can't alter the "wrapping" Just in this case.

您的appFunc需要纯值才能以包装"形式产生某些东西.那不是适用的.在这里,我们需要对这些值进行一些计算,以了解包装"的组成部分是什么.

Your appFunc on the other hand, needs pure values to produce something in a "wrapping". That's not applicative. Here we need to do some calculations with the values, to know, what a constituent part of the "wrapping" will be.

让我们看一下中央单子手术:

Let's look at the central monadic operation:

(>>=) :: Monad m => m a -> (a -> m b) -> m b

第二个参数正是这样做的.它是一个函数,它采用纯值并在包装中返回某些内容.就像appFunc i1 i2.

Here the second parameter does exactly that. It is a function taking a pure value and returning something in a wrapping. Just like appFunc i1 i2.

这篇关于有关适用性和嵌套Maybe的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆