Posted on 2018-07-06 by Oleg Grenrus

Today I experimented with upcoming GHC-8.6 feature: Source Plugins. In GHC 8.6 plugin functionality is extended, so there are more hooks where we can add own processing of the AST: after parsing, renaming or type-checking. For idiom brackets we'll change the AST right after the parsing step.

Idiom brackets (introduced in Applicative programming with effects paper) is a syntax extension to write Applicative expressions without drowning into <*> . The Strathclyde Haskell Enhancement also supports idiom brackets, but with different syntax. The point my plugin tries to solve: a lot of preprocessors can be built using GHC for the boring parts (like parsing).

As nobody (?) writes their lists as ([1, 2, 3]) , we can steal that syntax! (Note: I don't know how to ignore, or lift pure values, ideas welcome)

{-# OPTIONS -fplugin=IdiomsPlugin #-} -- | Hack idiom-brackets using Source Plugin. -- module Main (main) where main :: IO () main = do -- Just "foobar" print ([ mappend ( Just "foo" ) ( Just "bar" ) ]) -- Nothing print ([ const ( Just "foo" ) Nothing ]) -- Just 3 print ([ ( + ) ( Just 1 ) ( Just ( 2 :: Int )) ]) -- Just True print ([ Just True || Just False ]) -- [1,2,3], because `pure 1` can be specialised to [1] -- and non singleton lists are not transformed print $ ([ 1 ]) ++ ([ 2 , 3 ]) ++ ([])

The implementation is on GitHub: https://github.com/phadej/idioms-plugins

It's not complicated, little over hundred lines right now. Some highlights:

Scrap Your Boilerplate let us transform only the matching intersting nodes of AST by transform = SYB.everywhereM (SYB.mkM transform') where transform' :: LHsExpr GhcPs -> GHC.Hsc ( LHsExpr GhcPs ) transform' ... = ...

We can print legin looking warnings by dflags <- GHC.getDynFlags liftIO $ GHC.putLogMsg dflags GHC.NoReason Err.SevWarning l (GHC.defaultErrStyle dflags) $ text "expression" <+> ppr x <+> text "looks weird" where pretty-printing combinators are defined in Outputable module. And more generally, a lot of things can be converted to String with showPpr dflags theThing (not Show ).

I invite you to look through the implementation, think about what else Source Plugins can be used for, and implementing those ideas!

Please ask me questions (e.g. on twitter I'm @phadej), if I cannot answer them myself, I'll find someone who can!