如何减去 Haskell 中的 Maybe 值?例如,如果我想减去 Just 8 - Just 5 得到 Just 3,我该怎么做?
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?
我怎样才能做到以下几点。例如,如果我想减去 Just 8
- Just 5
得到 Just 3
,我该怎么做?
Just 8 - Just 5 = Just 3
Just 15 - Just 9 = Just 6
import Control.Applicative
main = print $ liftA2 (-) (Just 8) (Just 5)
liftA2
函数(从 Control.Applicative
导入)"lifts" 普通函数到 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
等等
使用 monad 理解:
{-# 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)
returns 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
这是一个本质上 monadic 操作,它不能用应用程序编码,任何其他替代方式写下来肯定会更冗长。
一般来说,您应该使用单子方法:
Just 8 >>= \n -> Just 5 >>= \m -> return (n-m)
然而,在不涉及 monad 的情况下,我们仍然可以通过使用 Maybe
类型的仿函数和应用实例来完成这项工作。
首先让我们 fmap
对 Just 8
值的 (-)
运算符,例如 (-) <$> 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")
我怎样才能做到以下几点。例如,如果我想减去 Just 8
- Just 5
得到 Just 3
,我该怎么做?
Just 8 - Just 5 = Just 3
Just 15 - Just 9 = Just 6
import Control.Applicative
main = print $ liftA2 (-) (Just 8) (Just 5)
liftA2
函数(从 Control.Applicative
导入)"lifts" 普通函数到 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
等等
使用 monad 理解:
{-# 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)
returns 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
这是一个本质上 monadic 操作,它不能用应用程序编码,任何其他替代方式写下来肯定会更冗长。
一般来说,您应该使用单子方法:
Just 8 >>= \n -> Just 5 >>= \m -> return (n-m)
然而,在不涉及 monad 的情况下,我们仍然可以通过使用 Maybe
类型的仿函数和应用实例来完成这项工作。
首先让我们 fmap
对 Just 8
值的 (-)
运算符,例如 (-) <$> 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")