根据我的理解,Maybe类型可以与其他类型结合使用。它允许您使用" Just ... Nothing"为您组合输入的条件。格式。
我演讲幻灯片中的一个例子是Haskell中的一个函数,它给出了输入的平方根,但在此之前,检查输入是否为正。:
maybe_sqrt :: Maybe Float -> Maybe Float
maybe_sqrt maybe_x = case maybe_x of
Just x
| x >= 0 -> Just (sqrt x)
| otherwise -> Nothing
Nothing -> Nothing
但是,我不明白为什么这个功能同时使用案件和警卫。为什么你不能像这样使用警卫?:
maybe_sqrt :: Maybe Float -> Maybe Float
maybe_sqrt x
| x >= 0 = Just (sqrt x)
| otherwise = Nothing
答案 0 :(得分:8)
结合使用
Maybe
类型可以与其他类型
Maybe
不类型†。它是一个类型构造函数,即您可以使用生成类型。例如,Maybe Float
是一种类型,但它与Float
的类型不同。 Maybe Float
不能用作Float
,因为它可能不包含一个!{/ p>
但要计算平方根,需要Float
。好吧,没问题:在Just
的情况下,你可以通过模式匹配打开它!但是模式匹配会自动阻止您尝试从Float
中解除Nothing
的值,这个值不包含可以与任何内容进行比较的浮点数。
顺便说一下,这并不意味着您需要通过模式匹配跟踪每个可能的故障,一直到您的代码。幸运的是,Maybe
是一个单子。这意味着,如果您的功能是 Kleisli箭头
maybe_sqrt :: Float -> Maybe Float
maybe_sqrt x
| x >= 0 = Just (sqrt x)
| otherwise = Nothing
(这很好,因为它接受普通浮点数)然后你可以仍然使用Maybe Float
作为参数
GHCi> maybe_sqrt =<< Just 4
Just 2.0
GHCi> maybe_sqrt =<< Just (-1)
Nothing
GHCi> maybe_sqrt =<< Nothing
Nothing
† 正如评论中所讨论的那样,对于我们是否应该调用Maybe
类型,或仅仅是,存在一些分歧。类型级实体。根据{{3}},将它称为类型实际上相当不错。
无论如何:我的观点是Maybe Float
不是“Maybe
类型(给出失败)和Float
类型(给出值)的OR组合”,但是全新类型,结构为Maybe a
,可选包含Float
元素。
答案 1 :(得分:3)
如果您的类型为maybe_sqrt :: Float -> Maybe Float
,那么您就是这样做的。
实际上,请考虑:如果输入为Nothing
,您的功能应该怎样做?可能你想要返回Nothing
- 但你的编译器为什么要知道呢?
&#34;选项的全部内容&#34;类似Maybe
的类型是您无法忽略它 - 您需要处理所有情况。如果您希望Nothing
个案例落到Nothing
输出,Haskell为此提供了(某种程度上)方便的工具:
maybe_sqrt x_in = do
x <- x_in
if x >= 0 then return sqrt x
else Nothing
这是Maybe
的{{1}}个实例,它会执行您可能想要的操作。只要您有Monad
表达式,就可以仅使用Maybe T
提取成功的Just
个案。唯一要记住的是非 - pattern <- expression
绑定应该使用Maybe
代替。
答案 2 :(得分:2)
这是一个扩展的评论而不是一个答案。如左下图所示,Maybe
是Monad
的实例。它也是Alternative
的一个实例。如果您愿意,可以使用此事实来实现您的功能:
maybe_sqrt :: Maybe Float -> Maybe Float
maybe_sqrt maybe_x = do
x <- maybe_x
guard (x >= 0)
pure (sqrt x)
答案 3 :(得分:0)
这也更多是扩展评论(如果这是您第一次使用Maybe
,您可能还没有遇到类型类;当您这样做时回来)。正如其他人已经说过的那样,x
的类型为Maybe Float
。但写x >= 0
并不要求x
为Float
。它究竟需要什么? >=
具有类型(Ord a) => a -> a -> Bool
,这意味着它适用于Ord
类型类的实例的任何类型(并且Maybe Float
是一个),并且两个参数必须具有相同的类型。因此0
也必须是Maybe Float
!如果Maybe Float
属于Num
类型类,那么Haskell实际上允许这样做:它不在标准库中,但你可以自己定义一个实例:
instance Num a => Num (Maybe a) where
fromInteger x = Just (fromInteger x)
# this means 0 :: Maybe Float is Just 0.0
negate (Just x) = Just (negate x)
negate Nothing = Nothing
Just x + Just y = Just (x + y)
_ + _ = Nothing
# or simpler:
# negate = fmap negate
# (+) = liftA2 (+)
# similar for all remaining two argument functions
...
现在x >= 0
是有意义的。 sqrt x
不是;您还需要Floating
和Fractional
的实例。当然,Just (sqrt x)
将是Maybe (Maybe a)
,而不是Maybe a
!但只有sqrt x
才能做你想做的事。
问题在于Nothing >= 0
False
是巧合的。如果您选中了x <= 0
,则会Nothing
通过。
此外,定义&#34;孤立实例&#34;通常也是一个坏主意:即上面的实例实际上只应在定义Maybe
或的模块中定义em>在定义Num
的模块中。