module Telomare.Optimizer where

import Control.Lens.Plated (transform)
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Set (Set)
import qualified Data.Set as Set

import Telomare (IExpr (..))

-- TODO think about how removing var indexing will make it hard to figure out closure arity
-- oh wait, closures will all take one argument and return one argument, and closure
-- rewriting can make it so that returned argument is ZeroType, as long as what we pass in
-- contains prerequisite closures.


-- IExpr annotated with unbound vars
data IExprV
  = VZero
  | VPair IExprV IExprV
  | VVar IExprV
  | VApp IExprV IExprV
  | VAnno IExprV IExprV
  | VGate IExprV
  | VLeft IExprV
  | VRight IExprV
  | VTrace IExprV
  | VClosure IExprV IExprV
  deriving (IExprV -> IExprV -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: IExprV -> IExprV -> Bool
$c/= :: IExprV -> IExprV -> Bool
== :: IExprV -> IExprV -> Bool
$c== :: IExprV -> IExprV -> Bool
Eq, Int -> IExprV -> ShowS
[IExprV] -> ShowS
IExprV -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [IExprV] -> ShowS
$cshowList :: [IExprV] -> ShowS
show :: IExprV -> String
$cshow :: IExprV -> String
showsPrec :: Int -> IExprV -> ShowS
$cshowsPrec :: Int -> IExprV -> ShowS
Show, Eq IExprV
IExprV -> IExprV -> Bool
IExprV -> IExprV -> Ordering
IExprV -> IExprV -> IExprV
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: IExprV -> IExprV -> IExprV
$cmin :: IExprV -> IExprV -> IExprV
max :: IExprV -> IExprV -> IExprV
$cmax :: IExprV -> IExprV -> IExprV
>= :: IExprV -> IExprV -> Bool
$c>= :: IExprV -> IExprV -> Bool
> :: IExprV -> IExprV -> Bool
$c> :: IExprV -> IExprV -> Bool
<= :: IExprV -> IExprV -> Bool
$c<= :: IExprV -> IExprV -> Bool
< :: IExprV -> IExprV -> Bool
$c< :: IExprV -> IExprV -> Bool
compare :: IExprV -> IExprV -> Ordering
$ccompare :: IExprV -> IExprV -> Ordering
Ord)

{- TODO something to convert all closures that don't return zerotype to ones that do

  \a b -> (a,b) : D -> (D -> D)

  (\f x -> f x) ((\a b -> (a,b)) 0) 1

-}


-- converts nested grammar that can be computed locally
precompute :: IExpr -> IExpr
precompute :: IExpr -> IExpr
precompute = forall a. Plated a => (a -> a) -> a -> a
transform IExpr -> IExpr
f where
  f :: IExpr -> IExpr
f (PLeft (Pair IExpr
x IExpr
_))  = IExpr
x
  f (PRight (Pair IExpr
_ IExpr
x)) = IExpr
x
  f IExpr
x                   = IExpr
x

optimize :: IExpr -> IExpr
optimize :: IExpr -> IExpr
optimize = IExpr -> IExpr
precompute