packages feed

symantic-parser-0.1.0.20210201: src/Symantic/Parser/Haskell/Optimize.hs

{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE ViewPatterns #-}
module Symantic.Parser.Haskell.Optimize where

import Data.Bool (Bool(..))
import Data.Functor.Identity (Identity(..))
import Data.String (String)
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 Symantic.Univariant.Trans
import Symantic.Parser.Haskell.Term

-- * Type 'Term'
-- | Initial encoding of some 'Termable' symantics,
-- useful for some optimizations in 'optimizeTerm'.
data Term repr a where
  -- | Black-box for all terms neither interpreted nor pattern-matched.
  Term :: { unTerm :: repr a } -> Term repr a

  -- Terms useful for 'optimizeTerm'.
  (:@) :: Term repr (a->b) -> Term repr a -> Term repr b
  Lam :: (Term repr a -> Term repr b) -> Term repr (a->b)
  Lam1 :: (Term repr a -> Term repr b) -> Term repr (a->b)
  Var :: String -> Term repr a

  -- Terms useful for prettier dumps.
  Char :: (TH.Lift tok, Show tok) => tok -> Term repr tok
  Cons :: Term repr (a -> [a] -> [a])
  Eq :: Eq.Eq a => Term repr (a -> a -> Bool)
  {-
  Const :: Term repr (a -> b -> a)
  Flip :: Term repr ((a -> b -> c) -> b -> a -> c)
  Id :: Term repr (a->a)
  (:$) :: Term repr ((a->b) -> a -> b)
  -- (:.) :: Term repr ((b->c) -> (a->b) -> a -> c)
-- infixr 0 :$
-- infixr 9 :.
  -}
infixl 9 :@

type instance Output (Term repr) = repr
instance Trans repr (Term repr) where
  trans = Term

instance Termable repr => Termable (Term repr) where
  lam     = Lam
  lam1    = Lam1
  (.@)    = (:@)
  cons    = Cons
  eq      = Eq
  unit    = Term unit
  bool b  = Term (bool b)
  char    = Char
  nil     = Term nil
  left    = Term left
  right   = Term right
  nothing = Term nothing
  just    = Term just
  const   = Lam1 (\x -> Lam1 (\_y -> x))
  flip    = Lam1 (\f -> Lam1 (\x -> Lam1 (\y -> f .@ y .@ x)))
  id      = Lam1 (\x -> x)
  ($)     = Lam1 (\f -> Lam1 (\x -> f .@ x))
  (.)     = Lam1 (\f -> Lam1 (\g -> Lam1 (\x -> f .@ (g .@ x))))

-- | Beta-reduce the left-most outer-most lambda abstraction (aka. normal-order reduction),
-- but to avoid duplication of work, only those manually marked
-- as using their variable at most once.
-- This is mainly to get prettier splices.
-- 
-- DOC: Demonstrating Lambda Calculus Reduction, Peter Sestoft, 2001,
-- https://www.itu.dk/people/sestoft/papers/sestoft-lamreduce.pdf
optimizeTerm :: Term repr a -> Term repr a
optimizeTerm = nor
  where
  -- | normal-order reduction
  nor :: Term repr a -> Term repr a
  nor = \case
    Lam f -> Lam (nor Fun.. f)
    Lam1 f -> Lam1 (nor Fun.. f)
    x :@ y -> case whnf x of
      Lam1 f -> nor (f y)
      x' -> nor x' :@ nor y
    x -> x
  -- | weak-head normal-form
  whnf :: Term repr a -> Term repr a
  whnf = \case
    x :@ y -> case whnf x of
      Lam1 f -> whnf (f y)
      x' -> x' :@ y
    x -> x

instance Trans (Term Identity) Identity where
  trans = \case
    Cons -> cons
    Char t -> char t
    Eq -> eq
    Term repr -> repr
    x :@ y -> Identity (runIdentity (trans x) (runIdentity (trans y)))
    Lam  f -> Identity (runIdentity Fun.. trans Fun.. f Fun.. Term Fun.. Identity)
    Lam1 f -> trans (Lam f)
    Var{} -> undefined
    {-
    Const -> const
    Flip -> flip
    Id -> id
    (:$) -> ($)
    -}
instance Trans (Term TH.CodeQ) TH.CodeQ where
  -- Superfluous pattern-matches are only
  -- out of a cosmetic concerns when reading *.dump-splices,
  -- not for optimizing, which is done in 'optimizeTerm'.
  trans = \case
    Cons :@ x :@ y -> [|| $$(trans x) : $$(trans y) ||]
    Cons :@ x -> [|| ($$(trans x) :) ||]
    Cons -> cons
    Char t -> char t
    Eq :@ x :@ y -> [|| $$(trans x) Eq.== $$(trans y) ||]
    Eq :@ x -> [|| ($$(trans x) Eq.==) ||]
    Eq -> eq
    Term repr -> repr
    -- (:$) :@ x -> [|| ($$(trans x) Fun.$) ||]
    -- (:.) :@ f :@ g -> [|| \xx -> $$(trans f) ($$(trans g) xx) ||]
    -- (:.) :@ (:.) -> [|| \f x -> (\g y -> (f x) (g y)) ||]
    -- (:.) :@ x :@ y -> [|| $$(trans x) Fun.. $$(trans y) ||]
    -- (:.) :@ x -> [|| ($$(trans x) Fun..) ||]
    -- (:.) :@ f -> [|| \g x -> $$(trans f) (g x) ||]
    -- (:.) -> (.)
    x :@ y -> [|| $$(trans x) $$(trans y) ||]
    Lam f -> [|| \x -> $$(trans (f (Term [||x||]))) ||]
    Lam1 f -> trans (Lam f)
    Var{} -> undefined
    {-
    Const -> const
    Flip -> flip
    Id -> id
    (:$) -> ($)
    -}
instance Trans (Term ValueCode) ValueCode where
  trans = \case
    Term x -> x
    Char c -> char c
    Cons -> cons
    Eq -> eq
    (:@) f x -> (.@) (trans f) (trans x)
    Lam f -> ValueCode
      { value = value Fun.. trans Fun.. f Fun.. Term Fun.. (`ValueCode` undefined)
      , code = [|| \x -> $$(code Fun.. trans Fun.. f Fun.. Term Fun.. (undefined `ValueCode`) Fun.$ [||x||]) ||]
      }
    Lam1 f -> trans (Lam f)
    Var{} -> undefined
    {-
    Const -> const
    Flip -> flip
    Id -> id
    (:$) -> ($)
    -}
instance Trans (Term ValueCode) (Term TH.CodeQ) where
  trans = \case
    Term x -> Term (code x)
    Char c -> char c
    Cons -> cons
    Eq -> eq
    (:@) f x -> (.@) (trans f) (trans x)
    Lam f -> Lam (\x -> trans (f (trans x)))
    Lam1 f -> Lam1 (\x -> trans (f (trans x)))
    Var v -> Var v
    {-
    Const -> const
    Flip -> flip
    Id -> id
    (:$) -> ($)
    -}
instance Trans (Term TH.CodeQ) (Term ValueCode) where
  trans = \case
    Term x -> Term (ValueCode undefined x)
    Char c -> char c
    Cons -> cons
    Eq -> eq
    (:@) f x -> (.@) (trans f) (trans x)
    Lam f -> Lam (\x -> trans (f (trans x)))
    Lam1 f -> Lam1 (\x -> trans (f (trans x)))
    Var v -> Var v
    {-
    Const -> const
    Flip -> flip
    Id -> id
    (:$) -> ($)
    -}