module Eval (flatten, reduceB, beta) where
import Defs
import Data.Maybe
import Data.List
import Control.Applicative
flatten :: [Defn] -> Maybe Lambda
flatten ds = flatten' <$> main
where
main = snd <$> find ((== "Main").fst) resolved
flatten' :: Lambda -> Lambda
flatten' (Free s) = fromMaybe (Free s) $ lookup s resolved
flatten' (Var s) = (Var s)
flatten' (Abs v b) = Abs v $ flatten' b
flatten' (App f a) = App (flatten' f) (flatten' a)
resolved = head $ drop 10 $ iterate (map (resolve' <$>)) ds -- I am a bad person... TODO
where
resolve' (Var v) = (Var v)
resolve' (Abs f b) = Abs f $ resolve' b
resolve' (App f ar) = App (resolve' f) (resolve' ar)
resolve' (Free f) = fromMaybe (Free f) $ lookup f ds
reduceB :: Lambda -> Lambda
reduceB l = go l (beta l)
where
go p Nothing = p
go _ (Just n) = go n (beta n)
beta :: Lambda -> Maybe Lambda
beta (Var _) = Nothing
beta (Free _) = Nothing
beta (Abs f b) = Abs <$> pure f <*> beta b
beta (App (Abs v b) ar) = Just $ replace b v ar
beta (App (Free f) ar) = App (Free f) <$> beta ar
beta (App f ar) = App <$> beta f <*> pure ar
replace :: Lambda -> Int -> Lambda -> Lambda
replace (App f a) s ar = App (replace f s ar) (replace a s ar)
replace (Free s) _ _ = Free s
replace (Var s) s' ar | s == s' = ar
| otherwise = Var s
replace (Abs s b) s' ar | s == s' = Abs s b
| otherwise = Abs s (replace b s' ar)