{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs            #-}
{-# LANGUAGE TypeFamilies     #-}

module ASTExamples where

import Data.Maybe (fromJust)
import Control.Arrow ((>>>))
import Control.Monad ((>=>))

import Base
import AST
import Compos
import Fold
import Zipper
import HZip
import Rewriting
import Rules

-- | Example expression

example = Let ("x" := Mul (Const 6) (Const 9))
              (Add (EVar "x") (EVar "y"))

-- | Renaming variables using 'compos'

renameVar :: Expr -> Expr
renameVar = renameVar' Expr
  where
    renameVar' :: Ix AST a => AST a -> a -> a
    renameVar' Var x = x ++ "_"
    renameVar' _   x = compos renameVar' x

-- | Test for 'renameVar'

testRename :: Expr
testRename = renameVar example

-- | Result of evaluating an expression

data family Value aT :: *
data instance Value Expr  =  EV  (Env -> Int)
data instance Value Decl  =  DV  (Env -> Env)
data instance Value Var   =  VV  Var

type Env = [(Var, Int)]

-- | Algebra for evaluating an expression

evalAlgebra :: Algebra AST Value
evalAlgebra _ =  
     tag (\ (K x)                   -> EV (const x))
  &  tag (\ (I (EV x) :*: I (EV y)) -> EV (\ env -> x env  +  y env))
  &  tag (\ (I (EV x) :*: I (EV y)) -> EV (\ env -> x env  *  y env))
  &  tag (\ (I (VV x))              -> EV (fromJust . lookup x))
  &  tag (\ (I (DV e) :*: I (EV x)) -> EV (\ env -> x (e env)))
  &  tag (\ (I (VV x) :*: I (EV v)) -> DV (\ env -> (x, v env) : env ))
  &  tag (\ (I (DV f) :*: I (DV g)) -> DV (g . f))
  &  tag (\ (K x)                   -> VV x)

-- | Evaluator

eval :: Expr -> Env -> Int
eval x = let (EV f) = fold evalAlgebra x in f

-- | Test for 'eval'

testEval :: Int
testEval = eval example [("y", -12)] 

-- | Test for the generic zipper

testZipper :: Maybe Expr
testZipper =
    enter Expr   >>>
    down         >=>
    down         >=>
    right        >=>
    update solve >>>
    leave        >>>
    return        $  example
  where
    solve :: AST ix -> ix -> ix
    solve Expr _ = Const 42
    solve _    x = x

-- | Testing generic equality of expressions.

testEqual = (geq Expr example example,                -- should be True
             geq Expr example (fromJust testZipper))  -- should be False

instance Rewrite AST -- That's a bit nasty, should probably remove it

-- | A rewrite rule for expressions.

inlineRule var expr = Let (var := expr) (EVar var) :~> expr

-- | An example expression that matches the rule.

example2 = Let ("x" := Mul (Const 6) (Const 9))
               (EVar "x")

-- | Testing generic rewriting

testRewriting = rewrite2 Expr inlineRule example2

-- This more flexible version does not type in GHC 6.8.3 .
-- But it does type under the HEAD (and in mine!).
--
-- testRewriting = rewrite (rule Expr inlineRule) example2



