Some questions on Atkey-style indexed monads

All, For some project, I'm considering (again) to use an indexed state monad, which are now somewhat ergonomic to use with QualifiedDo. When looking into existing packages exposing relevant types/classes, I had some questions: 1. These packages provide something like ``` class IxFunctor f where imap :: (a -> b) -> f i j a -> f i j b class IxFunctor f => IxApplicative f where ... ``` Is this `IxFunctor` actually required/useful? It seems to me the implementation of `imap` for some `IxFunctor f` would be equal to `fmap` in the `Functor` implementation for `forall i j. f i j`. Hence, can `IxFunctor` be dropped in lieu of ``` class (forall i j. Functor (f i j)) => IxApplicative f where ... ``` 2. Existing packages predate MonadFail and QualifiedDo. The latter requires (in some cases) an implementation of `fail` and `mfix` to be provided by the module also providing `>>=` etc. I was wondering whether or not there need to be (or can be) `IxMonadFail` and `IxMonadFix` classes like ``` class IxMonad m => IxMonadFail m where ifail :: String -> m i j a class IxMonad m => IxMonadFix m where ifix :: (a -> m i j a) -> m i j a ``` I'm not sure it "makes sense" to have an `ifail` which returns an `m i j a` vs. having only a `MonadFail` (and hence `fail`) implementation for `m i i` only, taking into account the requirement for `fail f >>= k` to be equal to `fail f`, hence `ifail f >>=: k` to be equal to `ifail f`. I think the above question boils down to: is there any use in having `ifail :: String -> m i j a` next to `fail :: String -> m i i a`, or should (i)fail always be state-type-preserving? Similar doubts about `IxMonadFix m` vs. `MonadFix (m i i)`. Thanks for any insights, Nicolas

On Sun, Dec 04, 2022 at 06:05:28PM +0100, Nicolas Trangez wrote:
For some project, I'm considering (again) to use an indexed state monad, which are now somewhat ergonomic to use with QualifiedDo.
When looking into existing packages exposing relevant types/classes, I had some questions:
1. These packages provide something like
``` class IxFunctor f where imap :: (a -> b) -> f i j a -> f i j b
class IxFunctor f => IxApplicative f where ... ```
Is this `IxFunctor` actually required/useful? It seems to me the implementation of `imap` for some `IxFunctor f` would be equal to `fmap` in the `Functor` implementation for `forall i j. f i j`. Hence, can `IxFunctor` be dropped in lieu of
``` class (forall i j. Functor (f i j)) => IxApplicative f where ... ```
I suspect QualifiedConstraints didn't exist at the time that class was introduced. I agree in modern GHC-flavoured Haskell the quantified constraint version is better. Tom

On Sun, 2022-12-04 at 21:08 +0000, Tom Ellis wrote:
On Sun, Dec 04, 2022 at 06:05:28PM +0100, Nicolas Trangez wrote:
For some project, I'm considering (again) to use an indexed state monad, which are now somewhat ergonomic to use with QualifiedDo.
When looking into existing packages exposing relevant types/classes, I had some questions:
1. These packages provide something like
``` class IxFunctor f where imap :: (a -> b) -> f i j a -> f i j b
class IxFunctor f => IxApplicative f where ... ```
Is this `IxFunctor` actually required/useful? It seems to me the implementation of `imap` for some `IxFunctor f` would be equal to `fmap` in the `Functor` implementation for `forall i j. f i j`. Hence, can `IxFunctor` be dropped in lieu of
``` class (forall i j. Functor (f i j)) => IxApplicative f where ... ```
I suspect QualifiedConstraints didn't exist at the time that class was introduced. I agree in modern GHC-flavoured Haskell the quantified constraint version is better.
Thanks, that confirms my intuition. Indeed, the aforementioned approach requires some language extensions not available when the existing packages were published. Cheers, Nicolas
participants (2)
-
Nicolas Trangez
-
Tom Ellis