Gabriella439 / Gabriella439/Haskell-MMorph-Library
`instance MFunctor t => MFunctor (Psi t) ...`
- Dominant language
- Haskell
- Stars
- 53
- Forks
- 24
- PR merge metrics
- No merged PRs in 30d
Description
It seems I very frequently run into trouble with `MFunctor` instances that carry an `MFunctor` constraint forward. This is probably not a legitimate type, but consider:
```
newtype Stream t m r = Stream {runStream :: m (Either r (t m (Stream t m r)))}
```
Writing a functor instance is simple
```
instance (Monad m, Functor (t m)) => Functor (Stream t m) where
fmap f = Stream . liftM (either (Left . f) (Right . fmap (fmap f))) . runStream
```
but if I set out to write
```
instance (MFunctor t) => MFunctor (Stream t) where
hoist phi = loop where
loop (Stream me) = Stream $ phi $ do
e <- me
case e of
Left r -> return $ Left r
Right tr -> return $ Right $ hoist phi (fmap loop tr)
```
of course I get the complaint that
```
Could not deduce (Functor (t m)) arising from a use of ‘loop’
from the context (MFunctor t)
```
But the constraint can't be added, since `m` is not in scope. One can do an end run around this:
```
newtype Stream t m r = Stream {runStream :: m (Either r (t m (Stream t m r)))}
class RFunctor t where
rmap :: forall m a b . Monad m => (a -> b) -> t m a -> t m b
instance RFunctor t => RFunctor (Stream t) where
rmap f = Stream . liftM (either (Left . f) (Right . rmap (rmap f))) . runStream
instance (Monad m, RFunctor t) => Functor (Stream t m) where fmap = rmap
instance (MFunctor t, RFunctor t) => MFunctor (Stream t) where
hoist phi = loop where
loop (Stream me) = Stream $ phi $ do
e <- me
case e of
Left r -> return $ Left r
Right tr -> return $ Right $ hoist phi (rmap loop tr)
```
Am I missing some simpler device? I have bumped to this more than once; maybe here I have a bad instance, but it will it think be a distraction to meditate on the particular case. It is fairly typical that you need a stronger fmap where you write `instance (MFunctor t) => MFunctor (... t ...)` since you can't presuppose `(forall m. Monad m => Functor (t m))`
It occurred to me that something like `RFunctor` (pardon the dumb name) could be a constraint on `MFunctor` or the slightly strengthened `fmap` could be included in its methods. But I don't know.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with the Stream, MFunctor, and proposed RFunctor examples in the issue to understand the constraint problem. Determine whether the library’s typeclass API should express the stronger mapping requirement; done requires an agreed design, documented behavior, and any corresponding implementation or tests identified by the maintainers.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- haskell
- Domain
- developer-experience
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100