{-# LANGUAGE CPP #-} {-# LANGUAGE NoMonomorphismRestriction #-} ------------------------------------------------------------------------------ -- | A typechecker plugin that can disambiguate "obvious" uses of effects in -- @in-other-words@. -- -- __Example:__ -- -- Consider the following program: -- -- @ -- foo :: 'Control.Effect.Eff' ('Control.Effect.State.State' Int) m => m () -- foo = 'Control.Effect.State.put' 10 -- @ -- -- What does this program do? Any human will tell you that it changes the state -- of the 'Int' to 10, which is clearly what's meant. -- -- Unfortunately, @in-other-words@ can't work this out on its own. Its reasoning is -- "maybe you wanted to change some other 'Control.Effect.State.State' effect which -- is /also/ a 'Num', but you just forgot to add a 'Eff' constraint -- for it." -- -- This is obviously insane, but it's the way the cookie crumbles. -- 'Control.Effect.Plugin' is a typechecker plugin which will disambiguate the above -- program (and others) so the compiler will do what you want. -- -- __Usage:__ -- -- Add the following line to your package configuration: -- -- @ -- ghc-options: -fplugin=Control.Effect.Plugin -- @ -- -- __Limitations:__ -- -- The 'Control.Effect.Plugin' will only disambiguate effects if there is exactly one -- relevant constraint in scope. For example, it will /not/ disambiguate the -- following program: -- -- @ -- bar :: 'Control.Effect.Effs' \'[ 'Control.Effect.State.State' Int, 'Control.Effect.State.State' Double ] m => m () -- bar = 'Control.Effect.State.put' 10 -- @ -- -- because it is now unclear whether you're attempting to set the 'Int' or the -- 'Double'. Instead, you can manually write a type application in this case. -- -- @ -- bar :: 'Control.Effect.Effs' \'[ 'Control.Effect.State.State' Int, 'Control.Effect.State.State' Double ] m => m () -- bar = 'Control.Effect.State.put' @Int 10 -- @ -- module Control.Effect.Plugin ( plugin ) where import Control.Effect.Plugin.Fundep import GhcPlugins ------------------------------------------------------------------------------ plugin :: Plugin plugin :: Plugin plugin = Plugin defaultPlugin { tcPlugin :: TcPlugin tcPlugin = Maybe TcPlugin -> TcPlugin forall a b. a -> b -> a const (Maybe TcPlugin -> TcPlugin) -> Maybe TcPlugin -> TcPlugin forall a b. (a -> b) -> a -> b $ TcPlugin -> Maybe TcPlugin forall a. a -> Maybe a Just TcPlugin fundepPlugin #if __GLASGOW_HASKELL__ >= 806 , pluginRecompile :: [CommandLineOption] -> IO PluginRecompile pluginRecompile = [CommandLineOption] -> IO PluginRecompile purePlugin #endif }