【发布时间】:2020-03-06 23:06:16
【问题描述】:
我该如何执行以下操作。例如,如果我想减去Just 8 - Just 5 得到Just 3,我该怎么做?
Just 8 - Just 5 = Just 3
Just 15 - Just 9 = Just 6
【问题讨论】:
我该如何执行以下操作。例如,如果我想减去Just 8 - Just 5 得到Just 3,我该怎么做?
Just 8 - Just 5 = Just 3
Just 15 - Just 9 = Just 6
【问题讨论】:
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
等等
【讨论】:
import Control.Applicative
main = print $ liftA2 (-) (Just 8) (Just 5)
【讨论】:
使用单子推导:
{-# 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
这是一个本质上的单子操作,它不能用应用程序来编码,任何其他的写下来的方式肯定会更冗长。
【讨论】:
一般来说,您应该使用一元方法:
Just 8 >>= \n -> Just 5 >>= \m -> return (n-m)
但是,在不涉及 monad 的情况下,我们仍然可以通过使用 Maybe 类型的函子和应用实例来完成这项工作。
首先让我们在Just 8 值上使用fmap (-) 运算符,例如(-) <$> Just 8。这将产生Maybe 类型的应用程序,即Just (8-) 和类型签名Just (8-) :: Num a => Maybe (a -> a)。现在只需要一个应用操作即可完成工作:
λ> (-) <$> (Just 8) <*> (Just 5)
Just 3
这有时由LiftA2 完成,如其他一些答案所示,但我认为最好首先了解这种模式,因为LiftA2 硬连线到二元运算符/函数,换句话说,如果你必须解除三元运算符如(,,) 那么你需要使用LiftA3 来代替。然而,上面的模式只是以同样的方式完成它,比如
λ> (,,) <$> Just 1 <*> Just 't' <*> Just "yeah"
Just (1,'t',"yeah")
【讨论】: