{-# LANGUAGE DefaultSignatures #-} {-# LANGUAGE TemplateHaskell #-} -- | Haskell terms which are interesting -- to pattern-match when optimizing. module Symantic.Parser.Haskell.Term where import Data.Bool (Bool(..)) import Data.Either (Either(..)) import Data.Eq (Eq) import Data.Maybe (Maybe(..)) import Data.Functor.Identity (Identity(..)) import Prelude (undefined) import Text.Show (Show(..)) import qualified Data.Eq as Eq import qualified Data.Function as Fun import qualified Language.Haskell.TH as TH import qualified Language.Haskell.TH.Syntax as TH import qualified Symantic.Univariant.Trans as Sym -- * Class 'Termable' -- | Single-out some Haskell terms in order to class Termable repr where -- | Application, aka. unabstract. (.@) :: repr (a->b) -> repr a -> repr b -- | Lambda term abstraction, in HOAS (Higher-Order Abstract Syntax) style. lam :: (repr a -> repr b) -> repr (a->b) -- | Like 'lam' but whose argument is used only once, -- hence safe to beta-reduce (inline) without duplicating work. lam1 :: (repr a -> repr b) -> repr (a->b) -- Singled-out terms bool :: Bool -> repr Bool char :: (TH.Lift tok, Show tok) => tok -> repr tok cons :: repr (a -> [a] -> [a]) nil :: repr [a] eq :: Eq a => repr (a -> a -> Bool) unit :: repr () left :: repr (l -> Either l r) right :: repr (r -> Either l r) nothing :: repr (Maybe a) just :: repr (a -> Maybe a) const :: repr (a -> b -> a) flip :: repr ((a -> b -> c) -> b -> a -> c) id :: repr (a->a) (.) :: repr ((b->c) -> (a->b) -> a -> c) ($) :: repr ((a->b) -> a -> b) default (.@) :: Sym.Liftable2 repr => Termable (Sym.Output repr) => repr (a->b) -> repr a -> repr b default lam :: Sym.Liftable repr => Sym.Unliftable repr => Termable (Sym.Output repr) => (repr a -> repr b) -> repr (a->b) default lam1 :: Sym.Liftable repr => Sym.Unliftable repr => Termable (Sym.Output repr) => (repr a -> repr b) -> repr (a->b) default bool :: Sym.Liftable repr => Termable (Sym.Output repr) => Bool -> repr Bool default char :: Sym.Liftable repr => Termable (Sym.Output repr) => TH.Lift tok => Show tok => tok -> repr tok default cons :: Sym.Liftable repr => Termable (Sym.Output repr) => repr (a -> [a] -> [a]) default nil :: Sym.Liftable repr => Termable (Sym.Output repr) => repr [a] default eq :: Sym.Liftable repr => Termable (Sym.Output repr) => Eq a => repr (a -> a -> Bool) default unit :: Sym.Liftable repr => Termable (Sym.Output repr) => repr () default left :: Sym.Liftable repr => Termable (Sym.Output repr) => repr (l -> Either l r) default right :: Sym.Liftable repr => Termable (Sym.Output repr) => repr (r -> Either l r) default nothing :: Sym.Liftable repr => Termable (Sym.Output repr) => repr (Maybe a) default just :: Sym.Liftable repr => Termable (Sym.Output repr) => repr (a -> Maybe a) default const :: Sym.Liftable repr => Termable (Sym.Output repr) => repr (a -> b -> a) default flip :: Sym.Liftable repr => Termable (Sym.Output repr) => repr ((a -> b -> c) -> b -> a -> c) default id :: Sym.Liftable repr => Termable (Sym.Output repr) => repr (a->a) default (.) :: Sym.Liftable repr => Termable (Sym.Output repr) => repr ((b->c) -> (a->b) -> a -> c) default ($) :: Sym.Liftable repr => Termable (Sym.Output repr) => repr ((a->b) -> a -> b) (.@) = Sym.lift2 (.@) lam f = Sym.lift (lam (Sym.trans Fun.. f Fun.. Sym.trans)) lam1 f = Sym.lift (lam1 (Sym.trans Fun.. f Fun.. Sym.trans)) bool = Sym.lift Fun.. bool char = Sym.lift Fun.. char cons = Sym.lift cons nil = Sym.lift nil eq = Sym.lift eq unit = Sym.lift unit left = Sym.lift left right = Sym.lift right nothing = Sym.lift nothing just = Sym.lift just const = Sym.lift const flip = Sym.lift flip id = Sym.lift id (.) = Sym.lift (.) ($) = Sym.lift ($) infixr 0 $ infixr 9 . infixl 9 .@ -- * Type 'ValueCode' data ValueCode a = ValueCode { value :: a , code :: TH.CodeQ a } instance Termable ValueCode where f .@ x = ValueCode { value = runIdentity (Identity (value f) .@ (Identity (value x))) , code = code f .@ code x } lam f = ValueCode { value = runIdentity (lam (Identity Fun.. value Fun.. f Fun.. (`ValueCode` undefined) Fun.. runIdentity)) , code = lam (code Fun.. f Fun.. ValueCode undefined) } lam1 = lam bool b = ValueCode (runIdentity (bool b)) (bool b) char c = ValueCode (runIdentity (char c)) (char c) cons = ValueCode (runIdentity cons) cons nil = ValueCode (runIdentity nil) nil eq = ValueCode (runIdentity eq) eq unit = ValueCode (runIdentity unit) unit left = ValueCode (runIdentity left) left right = ValueCode (runIdentity right) right nothing = ValueCode (runIdentity nothing) nothing just = ValueCode (runIdentity just) just const = ValueCode (runIdentity const) const flip = ValueCode (runIdentity flip) flip id = ValueCode (runIdentity id) id ($) = ValueCode (runIdentity ($)) ($) (.) = ValueCode (runIdentity (.)) (.) instance Termable Identity where f .@ x = Identity (runIdentity f (runIdentity x)) lam f = Identity (runIdentity Fun.. f Fun.. Identity) lam1 = lam bool = Identity char = Identity cons = Identity (:) nil = Identity [] eq = Identity (Eq.==) unit = Identity () left = Identity Left right = Identity Right nothing = Identity Nothing just = Identity Just const = Identity Fun.const flip = Identity Fun.flip id = Identity Fun.id ($) = Identity (Fun.$) (.) = Identity (Fun..) instance Termable TH.CodeQ where (.@) f x = [|| $$f $$x ||] lam f = [|| \x -> $$(f [||x||]) ||] lam1 = lam bool b = [|| b ||] char c = [|| c ||] cons = [|| (:) ||] nil = [|| [] ||] eq = [|| (Eq.==) ||] unit = [|| () ||] left = [|| Left ||] right = [|| Right ||] nothing = [|| Nothing ||] just = [|| Just ||] const = [|| Fun.const ||] id = [|| \x -> x ||] flip = [|| \f x y -> f y x ||] ($) = [|| (Fun.$) ||] (.) = [|| (Fun..) ||]