第一次在Haskell中使用Maybe类型,我的理解错了吗?

时间:2016-03-15 18:41:29

标签: haskell

根据我的理解,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

4 个答案:

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

这是一个扩展的评论而不是一个答案。如左下图所示,MaybeMonad的实例。它也是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 并不要求xFloat。它究竟需要什么? >=具有类型(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不是;您还需要FloatingFractional的实例。当然,Just (sqrt x)将是Maybe (Maybe a),而不是Maybe a!但只有sqrt x才能做你想做的事。

问题在于Nothing >= 0 False是巧合的。如果您选中了x <= 0,则会Nothing通过。

此外,定义&#34;孤立实例&#34;通常也是一个坏主意:即上面的实例实际上只应在定义Maybe 在定义Num的模块中。