{-# LANGUAGE NoMonomorphismRestriction #-} -- * Demonstrating `non-compositional', context-sensitive processing -- * The final style, via the intermediate data type. -- This is cheating. But it does show the relationship between -- initial and final. It also points out that everything we can -- do with the data type, we can do in the final approach too -- albeit -- with cheating in this case module PushNegFI where -- Explain the imports: import Intro2 hiding (main) -- The final representation of Exp import Intro1 (Exp(..)) -- import the Exp data type import qualified PushNegI as I -- use the initial push_neg as it was -- * // -- We write the interpreter for final terms that produce initial, data type -- terms instance ExpSYM Exp where lit = Lit -- nice symmetry between upper-and neg = Neg -- lower case add = Add initialize :: Exp -> Exp initialize = id -- * // -- We write an evaluator for data type that produces final representation -- The analogy with fold must be patent. finalize :: ExpSYM repr => Exp -> repr -- could have been inferred finalize (Lit n) = lit n finalize (Neg e) = neg (finalize e) finalize (Add e1 e2) = add (finalize e1) (finalize e2) -- * // -- Now, push_neg in the final style is a mere composition push_neg = finalize . I.push_neg . initialize -- * Deforestation? Fusion laws? -- Open research question: can the intermediate Exp data type be removed -- by deforestation? Can we propose fusion laws to eliminate Exp? -- * // -- To remind, here is our sample term tf1_view = view tf1 -- "(8 + (-(1 + 2)))" tf1_norm = push_neg tf1 -- The new expression can be evaluated with any interpreter tf1_norm_view = view tf1_norm -- "(8 + ((-1) + (-2)))" -- The result of the standard evaluation (the `meaning') is preserved tf1_norm_eval = eval tf1_norm -- 5 -- Add an extra negation tf1n_norm = push_neg (neg tf1) -- see the result tf1n_norm_view = view tf1n_norm -- "((-8) + (1 + 2))" tf1n_norm_eval = eval tf1n_norm -- -5 -- Negate the already negated term tf1nn_norm = push_neg (neg tf1n_norm) tf1nn_norm_view = view tf1nn_norm -- "(8 + ((-1) + (-2)))" -- * Dictionary translation of ExpSYM repr => repr data ExpSYMDict repr = ExpSYMDict{ lit_dict :: Int -> repr, neg_dict :: repr -> repr, add_dict :: repr -> repr -> repr} type FinTerm repr = ExpSYMDict repr -> repr -- The evaluator eval_dict :: ExpSYMDict Int eval_dict = ExpSYMDict {lit_dict = id, neg_dict = (\x -> -x), add_dict = (+)} -- Our sample expression in the final form -- tf1 = add (lit 8) (neg (add (lit 1) (lit 2))) tf1' :: FinTerm repr tf1' dict = add_dict dict (lit_dict dict 8) (neg_dict dict (add_dict dict (lit_dict dict 1) (lit_dict dict 2))) tf1'_eval = tf1' eval_dict -- 5 main = do print PushNegFI.tf1_view print tf1_norm_view print tf1n_norm_view if tf1_norm_view == tf1nn_norm_view then return () else error "Double neg" print tf1nn_norm_view if eval tf1 == tf1_norm_eval then return () else error "Normalization" if eval tf1 == - tf1n_norm_eval then return () else error "Normalization" print tf1'_eval