试图了解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
块的范围内进行这样的操作来产生汇总值吗?
答案 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)