{-# LANGUAGE NoMonomorphismRestriction #-} {-# LANGUAGE TypeSynonymInstances #-} -- * Tagless Typed Interpreters: extensibility module ExtF where import Intro2 as F hiding (main) -- We extend the final representation of the language with a new -- expression form: multiplication class MulSYM repr where mul :: repr -> repr -> repr -- An extended sample expression tfm1 = add (lit 7) (neg (mul (lit 1) (lit 2))) -- We can even use a previously defined unextended expression (tf1) -- as a part of the extended expression. -- We can indeed mix-and-match tfm2 = mul (lit 7) tf1 -- * // -- We extend the specific interpreters thusly instance MulSYM Int where mul e1 e2 = e1 * e2 -- The definition of eval stays the same. Why? -- * The extension _automatically_ kicks in tfm1_eval = eval tfm1 -- 5 tfm2_eval = eval tfm2 -- 35 -- We `extend' the view interpreter just as well instance MulSYM String where mul e1 e2 = "(" ++ e1 ++ " * " ++ e2 ++ ")" tfm1_view = view tfm1 -- "(7 + (-(1 * 2)))" tfm2_view = view tfm2 -- "(7 * (8 + (-(1 + 2))))" -- * // -- We can put the original, unextended expressions (F.tf1 from Intro2.hs) -- and the extended ones (which we have just defined) -- into the same list tfl1 = [F.tf1] -- old expression tfl2 = tfm1 : tfm2 : tfl1 -- add extended expressions -- The inferred type of tfl2 is insightful: -- *ExtF> :t tfl1 -- tfl1 :: (ExpSYM repr) => [repr] -- *ExtF> :t tfl2 -- tfl2 :: (ExpSYM repr, MulSYM repr) => [repr] tfl2_eval = map eval tfl2 -- [5,35,5] tfl2_view = map view tfl2 -- ["(7 + (-(1 * 2)))","(7 * (8 + (-(1 + 2))))","(8 + (-(1 + 2)))"] main = do print tfm1_eval print tfm2_eval print tfm1_view print tfm2_view print tfl2_eval print tfl2_view