【问题标题】:How do I subtract Maybe values in Haskell? For example, if I want to subtract Just 8 - Just 5 to get Just 3, how would I do that?如何在 Haskell 中减去 Maybe 值?例如,如果我想减去 Just 8 - Just 5 得到 Just 3,我该怎么做?
【发布时间】:2020-03-06 23:06:16
【问题描述】:

我该如何执行以下操作。例如,如果我想减去Just 8 - Just 5 得到Just 3,我该怎么做?

Just 8 - Just 5 = Just 3

Just 15 - Just 9 = Just 6

【问题讨论】:

    标签: haskell monads maybe


    【解决方案1】:

    liftA2 函数(从 Control.Applicative 导入)将普通函数“提升”到 Applicative 上下文中。例如,liftA2 (-) 是一个函数,它接受的不是两个 Num a => a 值,而是两个 (Applicative f, Num a) => f a 值,并在相同的上下文中产生结果。这不仅适用于Maybe

    >>> liftA2 (-) (Just 8) (Just 5)
    Just 3
    

    但对于列表

    >>> liftA2 (-) [4,5,6] [1,2,3] -- difference of every pair with one number from each list
    [3,2,1,4,3,2,5,4,3]    
    

    Either:

    >>> liftA2 (-) (Right 8) (Right 5)
    Right 3
    

    功能

    >>> liftA2 (-) (+3) (*2) 9 -- (\x -> (x + 3) - (x * 2)) 9 == 12 - 18
    -6
    

    等等

    【讨论】:

      【解决方案2】:
      import Control.Applicative
      
      main = print $ liftA2 (-) (Just 8) (Just 5)
      

      【讨论】:

      • 你能举例说明它的使用方法吗?我试过了,得到错误'变量不在范围内'
      • 我相信 OP 会很感激对 WRT 函子、应用程序或提升函数的一点解释......
      • @Kau 是的,但是对于未来,我建议在这种情况下使用you ask Hoogle
      【解决方案3】:

      使用单子推导:

      {-# LANGUAGE MonadComprehensions #-}
      
      foo :: (Num b, Monad m) => m b -> m b -> m b
      foo a b = [ x - y | x <- a, y <- b ]
      

      不错,视觉效果,被低估了。

      foo (Just 8) (Just 5) 返回Just 3

      当然,在这种简单的情况下,它在语法上是多余的,你最好使用liftA2 (-),无论是在语义上还是在实践上。

      当你有一些条件计算时,monad 推导式真正闪耀的地方。经典的例子是安全除法,避免除以零错误:

      safediv :: (MonadPlus m, Fractional b, Eq b) 
              => m b -> m b -> m b
      safediv a b = [ x / y | x <- a, y <- b, y /= 0 ]
      
      -- safediv (Just 8) (Just 0)  returns  Nothing
      

      这是一个本质上的单子操作,它不能用应用程序来编码,任何其他的写下来的方式肯定会更冗长。

      【讨论】:

        【解决方案4】:

        一般来说,您应该使用一元方法:

        Just 8 >>= \n -> Just 5 >>= \m -> return (n-m)
        

        但是,在不涉及 monad 的情况下,我们仍然可以通过使用 Maybe 类型的函子和应用实例来完成这项工作。

        首先让我们在Just 8 值上使用fmap (-) 运算符,例如(-) &lt;$&gt; Just 8。这将产生Maybe 类型的应用程序,即Just (8-) 和类型签名Just (8-) :: Num a =&gt; Maybe (a -&gt; a)。现在只需要一个应用操作即可完成工作:

        λ> (-) <$> (Just 8) <*> (Just 5) 
        Just 3
        

        这有时由LiftA2 完成,如其他一些答案所示,但我认为最好首先了解这种模式,因为LiftA2 硬连线到二元运算符/函数,换句话说,如果你必须解除三元运算符如(,,) 那么你需要使用LiftA3 来代替。然而,上面的模式只是以同样的方式完成它,比如

        λ> (,,) <$> Just 1 <*> Just 't' <*> Just "yeah"
        Just (1,'t',"yeah")
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-07-24
          • 2017-04-28
          • 1970-01-01
          相关资源
          最近更新 更多