简体   繁体   English

将类型参数限制为Monoid

[英]Restricting type parameter to Monoid

I've previously defined a function which takes a list of Maybe s and turns it into a Maybe of a list, like so: 我之前已经定义了一个函数,它接受了一个Maybe s列表并将其转换为Maybe的列表,如下所示:

floop :: [Maybe a] -> Maybe [a]
floop [] = Just []
floop (Nothing:_) = Nothing
floop (Just x:xs) = fmap (x:) $ floop xs

Now I want to redefine it to be compatible with a larger class of containers, not just lists, and I've found that it needs to implement the functions foldr , mappend , mempty , fmap , and pure ; 现在我想重新定义它与更大类的容器兼容,而不仅仅是列表,我发现它需要实现foldrmappendmemptyfmappure函数; so I figure that the following type line would be appropriate: 所以我认为以下类型行是合适的:

floop :: (Foldable t, Functor t, Monoid t) => t (Maybe a) -> Maybe (t a)

As (I think) it ensures that those functions are implemented for the given container, however it leads to the following error: 正如(我认为)它确保为给定容器实现这些功能,但是它会导致以下错误:

Expecting one more argument to ‘t’
The first argument of ‘Monoid’ should have kind ‘*’,
  but ‘t’ has kind ‘* -> *’
In the type signature for ‘floop'’:
  floop' :: (Foldable t, Functor t, Monoid t) =>
            t (Maybe a) -> Maybe (t a)

After looking into it, I found Monoid 's kind is different to that of Functor and Foldable , but I can't see why that would be the case, nor how to correct the error. 在研究之后,我发现Monoid的种类与FunctorFoldable的种类不同,但我不明白为什么会出现这种情况,也不知道如何纠正错误。

For those interested, here's the current implementation: 对于那些感兴趣的人,这是当前的实现:

floop :: (Foldable t, Functor t, Monoid t) => t (Maybe a) -> Maybe (t a)
floop xs = let
                f :: (Foldable t, Functor t, Monoid t) => Maybe a -> Maybe (t a) -> Maybe (t a)
                f Nothing _ = Nothing
                f (Just x) ys = fmap (mappend $ pure x) ys
            in
                foldr f (Just mempty) xs

Note: I have been made aware that this already exists as a builtin function ( sequence ), but I intend to implement it as a learning exercise. 注意:我已经意识到这已经作为内置函数( sequence )存在,但我打算将其作为一个学习练习来实现。

Monoidal applicatives are described by the Alternative class, using (<|>) and empty instead of mappend and mempty : Monoidal应用程序由Alternative类描述,使用(<|>)empty而不是mappendmempty

floop :: (Foldable t, Alternative t) => t (Maybe a) -> Maybe (t a)
floop xs = let
                f :: (Foldable t, Alternative t) => Maybe a -> Maybe (t a) -> Maybe (t a)
                f Nothing _ = Nothing
                f (Just x) ys = fmap ((<|>) $ pure x) ys
            in
                foldr f (Just empty) xs 

This might be a good place to bring up hoogle . 这可能是一个提升hoogle的好地方。

Searching for t (ma)-> m (ta) returns sequenceA :: (Traversable t, Applicative f) => t (fa) -> f (ta) as the first result. 搜索t (ma)-> m (ta)返回sequenceA :: (Traversable t, Applicative f) => t (fa) -> f (ta)作为第一个结果。 This then leads to the Traversable type class which is fairly close to what you are looking for. 然后,这将导致Traversable类型,它与您正在寻找的相当接近。

As Lee said you could use the Alternative class which is the Applicative equivalent of Monoid. 正如Lee所说,你可以使用Alternative类,它是Monoid的应用等价物。 Slightly more generalized: 稍微宽泛一点:

sequence' :: (Alternative t, Foldable t, Applicative a) => t (a b) -> a (t b)
sequence' = foldr step (pure empty)
  where step = liftA2 prepend
        prepend = (<|>) . pure

Here prepend first wraps some single element into t so it can use (<|>) to prepend it. 这里prepend首先将一些单个元素包装到t中,因此它可以使用(<|>)来预先添加它。 liftA2 lets us abstract over the applicative a, you can imagine it as unwrapping two arguments, applying them to prepend and wrapping the result back up. liftA2让我们对应用程序a进行抽象,您可以将它想象为解开两个参数,将它们应用于前置并将结果包装回来。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM