您可以仅使用列表单声道来确定列表的最小值或最大值吗?

时间:2018-11-10 03:00:50

标签: haskell monads foldable

试图了解Monad和Foldable之间的关系。我知道Monad,Applicative和Functor类型类的值的一部分是它们将函数提升到结构之上的能力,但是如果我想为Monad中包含的值生成汇总值(例如,最小值或最大值)怎么办?

如果没有正确的累加器(如可折叠),这将是不可能的吗?要拥有蓄能器,您必须注入或破坏结构?

min :: Ord a => a -> a -> a

foldMin :: (Foldable t, Ord a) => t a -> Maybe a
foldMin t = foldr go Nothing t
  where
    go x Nothing = Just x
    go x (Just y) = Just (min x y)

这里,Nothing值是累加器。因此,不可能在do块的范围内进行这样的操作来产生汇总值吗?

3 个答案:

答案 0 :(得分:3)

我不确定自己是否理解这个问题,因此,如果这不是一个有用的答案,请原谅我,但是据我了解,问题的核心是:

  

因此不可能在do块的范围内执行这样的操作来生成汇总值吗?

正确,那是不可能的。 Haskell的do表示法是Monad之上的语法糖,因此基本上是>>=return之上的语法糖。

如您所知,

return不允许您“访问” Monad的内容,因此,对您拥有的内容的唯一访问权是通过>>=,然后在例如,在列表monad的情况下,一次只能给您一个值。

请注意,Foldable甚至不需要数据容器为Functor(更不用说Monad)了。众所周知,Set不是Functor实例,但是 Foldable实例。

例如,您可以在一组中找到最小值:

Prelude Data.Foldable Set> foldr (\x -> Just . maybe x (min x)) Nothing $ Set.fromList [42, 1337, 90125, 2112]
Just 42

答案 1 :(得分:3)

以下人为和低效的代码是我最接近“仅使用list monad”的代码。这可能不是OP所要寻找的,而是在这里。

我还利用head(如果需要总数可以用listToMaybe代替)和null。我还使用empty(您可以用[]代替)。

该代码通过不确定地选择元素m然后检查是否存在更大的元素来工作。这具有二次复杂性。

import Control.Applicative

maximum :: Ord a => [a] -> a
maximum xs = head maxima
   where
   isMax m = null $ do
      x <- xs
      if x > m
         then return x
         else empty
   maxima = do
      m <- xs   -- non deterministically pick a maximum
      if isMax m
         then return m
         else empty

答案 2 :(得分:0)

我也不确定实际的问题是什么,但是可以使用Monoid实例来隐藏对累加器的需求。然后,作为最小的示例,您可以使用foldMap中的Data.Foldable来映射和合并Foldable的所有值。例如:

data Min a = Min { getMin :: Maybe a } deriving Show

instance Ord a => Monoid (Min a) where
  mempty                                = Min Nothing
  mappend a (Min Nothing)               = a
  mappend (Min Nothing) b               = b
  mappend (Min (Just a)) (Min (Just b)) = Min (Just (min a b))

foldMin :: (Foldable t, Ord a) => t a -> Maybe a
foldMin = getMin . foldMap (Min . Just)