I've previously defined a function which takes a list of Maybes and turns it into a Maybe of a list, like so:
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; 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.
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.
Monoidal applicatives are described by the Alternative class, using (<|>) and empty instead of mappend and mempty:
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.
Searching for t (m a)-> m (t a) returns sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a) as the first result. This then leads to the Traversable type class which is fairly close to what you are looking for.
As Lee said you could use the Alternative class which is the Applicative equivalent of 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. 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.
Related
I have the following data type defined:
data SynthesisTreeResult comp a = CompNode (comp a) [SynthesisTreeResult comp a]
| InputLeaf Location
I want to be able to turn it into a list of type [comp a] using toList, which requires an instance of Foldable.
I tried to write an instance by implementing foldMap:
class Foldable f where
foldMap :: Monoid m => (a -> m) -> f a -> m
However, since comp :: * -> *, I have to write instance Foldable (SynthesisTreeResult comp) where ..., which causes foldMap to have following type
foldMap :: Monoid m => (a -> m) -> SynthesisTreeResult comp a -> m
But I need
foldMap :: Monoid m => (comp a -> m) -> SynthesisTreeResult comp a -> m
to be able to fold it.
Is it possible? Maybe I need to impose Functor on comp?
Thanks to #Willem Van Onsem hint, I figured out the proper instance:
instance Foldable comp => Foldable (SynthesisTreeResult comp) where
foldMap f (CompNode comp children) = mappend (foldMap f comp) $ mconcat $ map (foldMap f) children
Given your comment that you want a comp a instead of an a, you need to make a minor change to your type:
data SynthesisTreeResult t = CompNode t [SynthesisTreeResult t]
| InputLeaf Location
That's necessary because the type that comes out of foldMap is always the last type parameter of the type that went in. Fixing the usages of your type is easy; just change SynthesisTreeResult Foo Bar to SynthesisTreeResult (Foo Bar) everywhere. With that change, here's your Foldable instance:
instance Foldable SynthesisTreeResult where
foldMap f (CompNode x xs) = f x <> foldMap (foldMap f) xs
foldMap _ (InputLeaf _) = mempty
If that change to your type isn't acceptable, then you can't use Foldable to get what you want, and you need to write your own toList method, which you could do like this:
myToList :: SynthesisTreeResult comp a -> [comp a]
myToList (CompNode x xs) = x:concatMap myToList xs
myToList (InputLeaf _) = []
I recently read about recursion schemes where catamorphisms are described as analogous to generalized foldr.
Is is possible to write an instance of Foldable (via either foldr or foldMap) in terms of cata in all cases?
foldMap, being the fundamental operation of Foldable, is a better candidate for implementation than foldr. The answer is a qualified yes. cata only handles recursion; it doesn't tell you where to "find" all the values in a structure. (In the same way, implementing foldMap #[] with foldr still requires knowing the inner details of [].) Doing so requires a little help:
class Bifoldable f where
bifoldMap :: Monoid m => (a -> m) -> (b -> m) -> f a b -> m
You can then define
foldMapDefault ::
(Recursive (f a), Base (f a) ~ b a, Bifoldable b) =>
Monoid m => (a -> m) -> f a -> m
foldMapDefault f = cata (bifoldMap f id)
This allows you to do things like
data Tree a = Leaf | Branch (Tree a) a (Tree a)
makeBaseFunctor ''Tree
deriveBifoldable ''TreeF
instance Foldable Tree where foldMap = foldMapDefault
(Though you may as well have just said deriving Foldable on Tree.) For maximum genericity, you may want something more like this (I say "want"...)
newtype Fixed f a = Fixed { getFixed :: f a }
newtype Bibase f a b = Bibase { getBibase :: Base (f a) b }
instance (forall a. Recursive (f a), Bifoldable (Bibase f)) =>
Foldable (Fixed f) where
foldMap :: forall a m. Monoid m => (a -> m) -> Fixed f a -> m
foldMap f = cata (bifoldMap f id . Bibase #f #a #m) . getFixed
You can now say things like
data Tree a = Leaf | Branch (Tree a) a (Tree a)
makeBaseFunctor ''Tree
deriveBifoldable ''TreeF
deriving via TreeF instance Bifoldable (Bibase Tree)
deriving via (Fixed Tree) instance Foldable Tree
But now your Base functors can be more irregular:
data List a = Nil | Cons a (List a)
type instance Base (List a) = Compose Maybe ((,) a)
instance Recursive (List a) where
project Nil = Compose Nothing
project (Cons x xs) = Compose (Just (x, xs))
instance Bifoldable (Bibase List) where
bifoldMap f g (Bibase (Compose Nothing)) = mempty
bifoldMap f g (Bibase (Compose (Just (x, xs)))) = f x <> g xs
deriving via (Fixed List) instance Foldable List
You often can, but not universally. All it takes is a single counter-example. Several exist, but consider the simplest one that comes to (my) mind.
While completely unnecessary, you can define Boolean values with an F-algebra:
data BoolF a = TrueF | FalseF deriving (Show, Eq, Read)
instance Functor BoolF where
fmap _ TrueF = TrueF
fmap _ FalseF = FalseF
From this (as the linked article explains) you can derive the catamorphism:
boolF :: a -> a -> Fix BoolF -> a
boolF x y = cata alg
where alg TrueF = x
alg FalseF = y
The type Fix BoolF is isomorphic to Bool, which isn't parametrically polymorphic (i.e. it doesn't have a type parameter), yet a catamorphism exists.
The Foldable type class, on the other hand, is defined for a parametrically polymorphic container t, e.g.
foldr :: (a -> b -> b) -> b -> t a -> b
Since Bool isn't parametrically polymorphic, it can't be Foldable, yet a catamorphism exists. The same is true for Peano numbers.
For parametrically polymorphic types, on the other hand, you often (perhaps always?) can. Here's a Foldable instance for a tree defined with its catamorphism:
instance Foldable TreeFix where
foldMap f = treeF (\x xs -> f x <> fold xs)
Here's one for Maybe:
instance Foldable MaybeFix where
foldMap = maybeF mempty
and one for linked lists:
instance Foldable ListFix where
foldr = listF
I am trying to understand Traversable with the help of https://namc.in/2018-02-05-foldables-traversals.
Somewhere the author mentioned the following sentence:
Traversable is to Applicative contexts what Foldable is to Monoid
values.
What did he try to clarify?
I do not get the connection between Foldable to Monoid.
Please provide an example.
In the beginning, there was foldr:
foldr :: (a -> b -> b) -> b -> [a] -> b
and there was mapM:
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
foldr was generalized to data types other than [a] by letting each type define its own definition of foldr to describe how to reduce it to a single value.
-- old foldr :: (a -> b -> b) -> b -> [] a -> b
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
If you have a monoid, you don't have to specify a binary function, because the Monoid instance already provides its own starting value and knows how to combine two values, which is apparent from its default definition in terms of foldr:
-- If m is a monoid, it provides its own function of type b -> b.
foldMap :: (Foldable t, Monoid m) => (a -> m) -> t a -> m
foldMap f = foldr (mappend . f) mempty
Traverse does the same kind of generalization from lists to traversable types, but for mapM:
-- old mapM :: Monad m => (a -> m b) -> [] a -> m ([] b)
traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
(When mapM was first defined, there was no Applicative class; if there had been, mapA :: Applicative f => (a -> f b) -> [a] -> f [b] could have been defined instead; the Monad constraint was stronger than was necessary.)
An Applicative is monoidal in nature, so there was no need in Traverse for the type of distinction that foldr/foldMap draws.
The article (and the corresponding passage of the Wikibook) is talking about how the effects (or, to use the language seen there, the contexts) of applicative values can be combined monoidally. The connection with Foldable is that list-like folding is ultimately amounts to combining values monoidally (see chepner's answer, and also Foldr/Foldl for free when Tree is implementing Foldable foldmap?. As for the applicative contexts part, there are a few ways to look at that. One of them is noting that, for any Applicative f and Monoid m, f m is a monoid, with pure mempty as mempty and liftA2 mappend as mappend (this Ap type from the reducers package witnesses that). For a concrete example, let's pick f ~ Maybe and m ~ (). That leaves us with four possible combinations:
liftA2 mappend (Just ()) (Just ()) = Just ()
liftA2 mappend (Just ()) Nothing = Nothing
liftA2 mappend Nothing (Just ()) = Nothing
liftA2 mappend Nothing Nothing = Nothing
Now contrast with All, the Bool monoid with (&&) as mappend:
mappend (All True) (All True) = All True
mappend (All True) (All False) = All False
mappend (All False) (All True) = All False
mappend (All False) (All False) = All False
They match perfectly: Just () stands for True, Nothing for False, and liftA2 mappend for (&&).
Now let's have another look at the Wikibook example:
deleteIfNegative :: (Num a, Ord a) => a -> Maybe a
deleteIfNegative x = if x < 0 then Nothing else Just x
rejectWithNegatives :: (Num a, Ord a, Traversable t) => t a -> Maybe (t a)
rejectWithNegatives = traverse deleteIfNegative
GHCi> rejectWithNegatives [2,4,8]
Just [2,4,8]
GHCi> rejectWithNegatives [2,-4,8]
Nothing
The Maybe values generated by applying deleteIfNegative to the values in the lists are combined monoidally in the way shown above, so that we get a Nothing unless all the Maybe values are Just.
This matter can also be approached in the opposite direction. Through the Applicative instance for Const...
-- I have suppressed a few implementation details from the instance used by GHC.
instance Monoid m => Applicative (Const m) where
pure _ = Const mempty
Const x <*> Const y = Const (x `mappend` y)
... we can get an Applicative out of any Monoid, such that (<*>) combines the monoidal values monoidally. That makes it possible to define foldMap and friends in terms of traverse.
On a final note, the category theoretical description of Applicative as a class for monoidal functors involves something rather different from what I have covered here. For further discussion of this issue, and of other fine print, see Monoidal Functor is Applicative but where is the Monoid typeclass in the definition of Applicative? (if you want to dig deeper, it is well worth it to read all of the answers there).
I've simplified the type signature of some code I need, and it looks roughly like this:
Functor f => f (Maybe a, b) -> (Maybe (f a), f b)
Can I, how do I implement such a function? And if so, how? I'm half guessing I need to push the functor down using Traversable, but I'm having trouble putting this all together in my head.
Pushing f one level down can be done by:
fn :: Functor f => f (a, b) -> (f a, f b)
fn v = (fmap fst v, fmap snd v)
(Note that tuples are not traversable if you want both sides.)
The second part is
Functor f => f (Maybe a) -> Maybe (f a)
This type is only inhabited by const Nothing, because the only function you can apply to this value is fmap, getting a value of type f b for some b.
To illustrate why this second part is not possible, consider the fact that IO is an instance of Functor. If you could get a Maybe (IO a) from your value, applying isJust to it would leak one bit of information about the original IO (Maybe a) value without executing it.
We can do, if it is Traversable and not Functor.
fn :: Traversable t => t (Maybe a, b) -> (Maybe (t a), t b)
fn v = (sequenceA $ fmap fst v, fmap snd v)
Is it okay?
Foldable is a superclass of Traversable, similarly to how Functor is a superclass of Applicative and Monad.
Similar to the case of Monad, where it is possible to basically implement fmap as
liftM :: Monad m => (a->b) -> m a -> m b
liftM f q = return . f =<< q
we could also emulate foldMap as
foldLiftT :: (Traversable t, Monoid m) => (a -> m) -> t a -> m
foldLiftT f = fst . traverse (f >>> \x -> (x,x))
-- or: . sequenceA . fmap (f >>> \x -> (x, x))
using the Monoid m => (,) m monad. So the combination of superclass and methods bears in both cases a certain redundancy.
In case of monads, it can be argued that a “better” definition of the type class would be (I'll skip applicative / monoidal)
class (Functor m) => Monad m where
return :: a -> m a
join :: m (m a) -> m a
at least that's what's used in category theory. This definition does, without using the Functor superclass, not permit liftM, so it is without this redundancy.
Is a similar transformation possible for the Traversable class?
To clarify: what I'm after is a re-definition, let's call it,
class (Functor t, Foldable t) => Traversable t where
skim :: ???
such that we could make the actual Traverse methods top-level functions
sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a)
but it would not be possible to make generically
instance (Traversable t) => Foldable t where
foldMap = ... skim ...
data T
instance Traversable T where
skim = ...
I'm not asking because I need this for something particular; it's a conceptual question so as to better understand the difference between Foldable and Traversable. Again much like Monad vs Functor: while >>= is much more convenient than join for everyday Haskell programming (because you usually need precisely this combination of fmap and join), the latter makes it simpler to grasp what a monad is about.
Foldable is to Functor as Traversable is to Monad, i.e. Foldable and Functor are superclasses of Monad and Traversable (modulo all the applicative/monad proposal noise).
Indeed, that's already in the code
instance Foldable f => Traversable f where
...
So, it's not clear what more there is to want. Foldable is characterized by toList :: Foldable f => f a -> [a] while Traversable depends ultimately on not only being able to abstract the content as a list like toList does, but also to be able to extract the shape
shape :: Functor f => f a -> f ()
shape = fmap (const ())
and then recombine them
combine :: Traversable f => f () -> [a] -> Maybe (f a)
combine f_ = evalStateT (traverse pop f_) where
pop :: StateT [a] Maybe a
pop = do x <- get
case x of
[] = empty
(a:as) = set as >> return a
which depends on traverse.
For more information on this property see this blog post by Russell O'Connor.
Super hand-wavy because it's late, but the extra power that Traversable has over Foldable is a way to reconstruct the original structure. For example, with lists:
module MyTraverse where
import Data.Foldable
import Data.Traversable
import Control.Applicative
import Data.Monoid
data ListRec f x = ListRec
{ el :: f (Endo [x])
}
instance Applicative f => Monoid (ListRec f x) where
mempty = ListRec (pure mempty)
mappend (ListRec l) (ListRec r) =
ListRec (mappend <$> l <*> r)
toM :: Functor f => f b -> ListRec f b
toM this = ListRec $ (Endo . (:)) <$> this
fromM :: Functor f => ListRec f b -> f [b]
fromM (ListRec l) = flip appEndo [] <$> l
myTraverse :: Applicative f => (a-> f b) -> [a] -> f [b]
myTraverse f xs = fromM $ foldMap (toM . f) xs
I think this myTraverse behaves the same as traverse, using only the classes Applicative, Foldable, and Monoid. You could re-write it to use foldr instead of foldMap if you wanted to get rid of Monoid.
lists are easy because they're a flat structure. However, I strongly suspect that you could use a Zipper to get the proper reconstruction function for any structure (since zippers are generically derivable, they should always exists).
But even with a zipper, you don't have any way of indicating that structure to the monoid/function. Notionally, it seems Traversable adds something like
class Traversed t where
type Path t :: *
annotate :: t a -> [(Path t, a)]
fromKeyed :: [(Path t, a)] -> t a
this seems to overlap heavily with Foldable, but I think that's inevitable when trying to associate the paths with their constituent values.