在模式匹配幺mempty(Monoid mempty in pattern matching)

2019-09-22 00:37发布

我试着写一个广义的maximum一个类似的功能Prelude 。 我的第一个naiv的做法是这样的:
maximum' :: (F.Foldable a, Ord b) => ab -> Maybe b
maximum' mempty = Nothing
maximum' xs = Just $ F.foldl1 max xs

然而,当我测试它总是返回Nothing输入不分:
> maximum' [1,2,3]
> Nothing

现在我不知道是否有可能获得一个Monoid类实例的空值。 测试功能我写的正常工作:
getMempty :: (Monoid a) => a -> a
getMempty _ = mempty

> getMempty [1,2,3]
> []

我已经来看看这两个问题,但我并没有弄清楚答案如何解决我的问题:
写在Haskell也许最多可使用含半幺群
在空集哈斯克尔模式匹配

我将如何改写maximum'功能,得到它的工作?

Answer 1:

作为CA麦肯在他的评论中指出的那样,你不能在价值观,只有模式的模式匹配。

等式maximum' mempty = Nothing实际上相当于式maximum' x = Nothing 。 该参数被绑定到一个名称和Nothing返回。

这里有一个方法,使你的代码的工作:

maximum' :: (F.Foldable a, Ord b, Eq (a b), Monoid (a b)) => a b -> Maybe b
maximum' xs
  | xs == mempty = Nothing
  | otherwise    = Just $ F.foldl1 max xs

比如,你可以比较xs反对mempty 。 需要注意的是,我们需要一个Monoid约束能够在价值得到mempty :: abEq约束能够比较为好。

的其他更优雅,溶液将是使用一个折叠空和非空的情况下区分:

maximum'' :: (F.Foldable a, Ord b) => a b -> Maybe b
maximum'' xs = F.foldl max' Nothing xs
  where max' Nothing x = Just x
        max' (Just y) x = Just $ max x y


Answer 2:

有几个方法可以做到这一点(一个@opqdonut证明是好的)。 人们还可以做出“最大”幺身边Maybe ,并使用foldMap

newtype Maximum a = Max { unMaximum :: Maybe a }

instance (Ord a) => Monoid (Maximum a) where
  mempty = Max Nothing
  mappend (Max Nothing) b = b
  mappend a (Max Nothing) = a
  mappend (Max (Just a)) (Max (Just b)) = Max . Just $ (max a b)

maximum' = unMaximum . F.foldMap (Max . Just)


Answer 3:

有很多种方法,一种是(你提到)创建的实例Monoid 。 然而,我们需要将其包装到Maybe ,当我们有没有值来区分的情况。 实现可能是这样的:

import Data.Monoid (Monoid, mempty, mappend)
import qualified Data.Foldable as F

-- Either we have a maximum value, or Nothing, if the
-- set of values is empty.
newtype Maximum a = Maximum { getMaximum :: Maybe a }
    deriving (Eq, Ord, Read, Show)

instance Ord a => Monoid (Maximum a) where
    mempty                      = Maximum Nothing

    -- If one part is Nothing, just take the other one.
    -- If both have a value, take their maximum.
    (Maximum Nothing) `mappend` y    = y
    x `mappend` (Maximum Nothing)    = x
    (Maximum (Just x)) `mappend` (Maximum (Just y))
                                     = Maximum (Just $ x `max` y)


maximum' :: (F.Foldable t, Ord a) => t a -> Maximum a
maximum' = F.foldMap (Maximum . Just)


Answer 4:

正如许多人已经告诉你了,你不能在一个数值模式匹配。

由于人少告诉你,模式匹配,可以说是相当的哈斯克尔像Java语言对象字段:它是通过紧密耦合的代码用于内部消费的有价值的,但可能你不希望暴露给外部客户端代码的东西。 基本上,如果你让一段代码知道你的类型的构造函数,现在你可以永远不改变,其他部分的代码,即使你的类型的语义并没有真正改变改变这些构造函数。

最好的解决方案是真的只使用Foldable.foldr

maximum' :: (F.Foldable a, Ord b) => a b -> Maybe b
maximum' = F.foldr step Nothing
    where step x Nothing = Just x
          step x (Just y) = Just (max x y)

需要注意的是foldr是一个广义的析构函数消除Foldable实例:它的两个参数是“如何与非空做Foldable和“怎么做” mempty ,这是比较抽象的,可重复使用比模式匹配。



Answer 5:

怎么样

maximum' :: (Monoid (t a), F.Foldable t, Ord a, Eq (t a)) => t a -> Maybe a
maximum' xs
   | xs == mempty = Nothing
   | otherwise    = Just $ F.foldl1 max xs

你失踪的防护。

getEmpty功能,你不需要它。 只要使用mempty ,并允许它的类型推断。



文章来源: Monoid mempty in pattern matching