我试着写一个广义的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'
功能,得到它的工作?
作为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 :: ab
和Eq
约束能够比较为好。
的其他更优雅,溶液将是使用一个折叠空和非空的情况下区分:
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
有几个方法可以做到这一点(一个@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)
有很多种方法,一种是(你提到)创建的实例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)
正如许多人已经告诉你了,你不能在一个数值模式匹配。
由于人少告诉你,模式匹配,可以说是相当的哈斯克尔像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
,这是比较抽象的,可重复使用比模式匹配。
怎么样
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
,并允许它的类型推断。