Skip to content

Instantly share code, notes, and snippets.

@NicolasT
Created September 12, 2017 23:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NicolasT/1928d04cfea11a6de7a6c38821cbe2e7 to your computer and use it in GitHub Desktop.
Save NicolasT/1928d04cfea11a6de7a6c38821cbe2e7 to your computer and use it in GitHub Desktop.
Enhancing type inference of indexed monads, removing type annotations?
-- See below
-- {-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE RebindableSyntax #-}
{-# LANGUAGE ScopedTypeVariables #-}
import Prelude hiding ((>>=), (>>), return)
import qualified Prelude as P
import Data.Functor.Identity (Identity, runIdentity)
-- From 'indexed'
import Control.Monad.Indexed (IxMonad, IxPointed, (>>>=), ireturn)
import Control.Monad.Indexed.Trans (ilift)
-- From 'indexed-extras'
import Control.Monad.Indexed.State (IxMonadState, IxStateT, iget, iput, runIxStateT)
{- ============================== Library code ============================= -}
-- MTL-style class
class Monad m => MonadFoo m where
foo :: Int -> m Int
-- Instance for the IxStateT transformer, simply lifting, MTL/transformers-style
instance MonadFoo m => MonadFoo (IxStateT m i i) where
foo = ilift . foo
{- ========================================================================= -}
{- ============================ Application code =========================== -}
-- For RebindableSyntax
(>>=) :: IxMonad m => m i j a -> (a -> m j k b) -> m i k b
(>>=) = (>>>=)
(>>) :: IxMonad m => m i j a -> m j k b -> m i k b
a >> b = a >>= const b
return :: IxPointed m => a -> m i i a
return = ireturn
myAction :: forall m. -- i. -- See below
( IxMonadState m
-- Without AllowAmbiguousTypes:
-- Could not deduce (MonadFoo (m i0 i0))
-- , MonadFoo (m i i)
-- When commented out, AllowAmbiguousTypes enabled and the above
-- constraint not commented:
-- Could not deduce (MonadFoo (m Int Int))
-- Could not deduce (MonadFoo (m String String))
-- so these are required, the above constraint is useless (can be
-- removed), AllowAmbiguousTypes can be disabled, and no need to
-- declare the 'i' type
, MonadFoo (m Int Int)
, MonadFoo (m String String)
)
=> m Int Bool ()
myAction = do
i <- iget
-- Without annotation:
-- Could not deduce (MonadFoo (m Int j1))
r <- foo i :: m Int Int Int
iput (show r)
-- Without annotation:
-- Could not deduce (MonadFoo (m String j0))
r' <- foo (i + 1) :: m String String Int
iput $ r == 2 * i && r' == 2 * (i + 1)
-- Being less polymorphic only slightly helps:
-- No need to specify constraints for 'MonadFoo (m Int Int' and
-- 'MonadFoo (m String String)', only for 'm', but still the need to annotate
-- types of invocations of 'foo':
myAction' :: forall m. -- Note explicit forall and ScopedTypeVariables are still required
( MonadFoo m
)
=> IxStateT m Int Bool ()
myAction' = do
i <- iget
-- Without annotation:
-- Could not deduce (MonadFoo (IxStateT m Int j1))
r <- foo i :: IxStateT m Int Int Int
iput (show r)
-- Without annotation:
-- Could not deduce (MonadFoo (IxStateT m String j0))
r' <- foo (i + 1) :: IxStateT m String String Int
iput $ r == 2 * i && r' == 2 * (i + 1)
-- 'Custom' instances for my application's monads (;-))
instance MonadFoo Identity where
foo i = P.return $ 2 * i
instance MonadFoo IO where
foo i = (P.>>) (putStr $ unwords ["What's", show i, "* 2? "]) readLn
main :: IO ()
main = (P.>>)
(print $ runIdentity $ runIxStateT myAction 2)
(print =<< runIxStateT myAction' 2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment