snoyberg / mono-traversable

Type classes for mapping, folding, and traversing monomorphic containers
154 stars 67 forks source link

MonoApply #159

Open eschnett opened 6 years ago

eschnett commented 6 years ago

It seems that a type class

class MonoFunctor mono => MonoApply mono where
    liftF2 :: (Element mono -> Element mono -> Element mono) -> mono -> mono -> mono

would be convenient to have.

Since you can't store functions in a MonoFunctor, it seems that the obvious generalizations liftF3 etc. need to be defined manually, which is inconvenient.

An alternative and more generic definition could be

class MonoFunctor mono => MonoCotraversable mono where
    cotraverse :: (Foldable f, Functor f) => (f (Element mono) -> Element mono) -> f mono -> mono

I don't know whether the Functor constraint here is sufficient -- I've seen examples where others defined Cotraversable with a stronger Comonad constraint on f instead.

An example use case would be

data IntList = IntList [Int]
instance MonoFunctor IntList where
    type Element IntList = Int
    ofmap f (IntList xs) = IntList (map f xs)

instance MonoApply IntList where
    oliftF2 f (IntList xs) (IntList ys) = IntList (zipWith f xs ys)
max2 = oliftF2 max

instance MonoCotraversable IntList where
    ocotraverse f xss = IntList $ map f (sequenceA xss)
maxMany = ocotraverse maximum

Haskell has traverse f = sequenceA . fmap f. What I'm suggesting here is similar to cotraverse f = fmap f . sequenceA. Since MonoTraversable by construction can't offer sequenceA, it seems this should be provided explicitly.

snoyberg commented 6 years ago

I have to admit that I don't really understand this proposal, sorry.

On Wed, Jan 24, 2018 at 7:22 PM, Erik Schnetter notifications@github.com wrote:

It seems that a type class

class MonoFunctor mono => MonoApply mono where liftF2 :: (Element mono -> Element mono -> Element mono) -> mono -> mono -> mono

would be convenient to have.

Since you can't store functions in a MonoFunctor, it seems that the obvious generalizations liftF3 etc. need to be defined manually, which is inconvenient.

An alternative and more generic definition could be

class MonoFunctor mono => MonoCotraversable mono where cotraverse :: (Foldable f, Functor f) => (f (Element mono) -> Element mono) -> f mono -> mono

I don't know whether the Functor constraint here is sufficient -- I've seen examples where others defined Cotraversable with a stronger Comonad constraint on f instead.

An example use case would be

data IntList = IntList [Int] instance MonoFunctor IntList where type Element IntList = Int ofmap f (IntList xs) = IntList (map f xs)

instance MonoApply IntList where oliftF2 f (IntList xs) (IntList ys) = IntList (zipWith f xs ys) max2 = oliftF2 max

instance MonoCotraversable IntList where ocotraverse f xss = IntList $ map f (sequenceA xss) maxMany = ocotraverse maximum

Haskell has traverse f = sequenceA . fmap f. What I'm suggesting here is similar to cotraverse f = fmap f . sequenceA. Since MonoTraversable by construction can't offer sequenceA, it seems this should be provided explicitly.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/snoyberg/mono-traversable/issues/159, or mute the thread https://github.com/notifications/unsubscribe-auth/AADBBzcY4jyUvIkh7j7w9uYk3jf-H9Baks5tN2bGgaJpZM4Rrnq8 .