Skip to content

Instantly share code, notes, and snippets.

@wz1000

wz1000/expr.hs Secret

Created December 26, 2020 09:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wz1000/dc05c6150c1cca1b61b2e60a997654a7 to your computer and use it in GitHub Desktop.
Save wz1000/dc05c6150c1cca1b61b2e60a997654a7 to your computer and use it in GitHub Desktop.
{-# LANGUAGE RecursiveDo #-}
module Expr where
import Control.Monad.Trans.Reader
import Data.Map (Map)
import qualified Data.Map as Map
type Var = String
data Expr
= Add Expr Expr
| Lit Int
| Var Var
| Let Var Expr Expr
deriving Show
data Env a = Env { bindings :: Map Var a, recursiveBindings :: Map Var (Env a, Expr, Int) }
summarise :: Monoid a => (Int -> a) -> Expr -> a
summarise f e = runReader (go e) (Env Map.empty Map.empty)
where
go (Add a b) = mappend <$> go a <*> go b
go (Lit i) = pure $ f i
go (Var v) = do
binds <- asks bindings
pure (binds Map.! v)
go (Let v e' e) = do
a <- go e'
local (\e -> e {bindings = Map.insert v a (bindings e) })
(go e)
type UnrollLimit = Int
-- Unroll recursive let up to limit, then use `f 0`
summariseRec :: Monoid a => UnrollLimit -> (Int -> a) -> Expr -> a
summariseRec lim f e = runReader (go e) (Env Map.empty Map.empty)
where
go (Add a b) = mappend <$> go a <*> go b
go (Lit i) = pure $ f i
go (Var v) = do
binds <- asks bindings
case Map.lookup v binds of
Just x -> pure x
Nothing -> do
recs <- asks recursiveBindings
let (env,expr,i) = recs Map.! v
if i < lim
then local (\_ -> env { recursiveBindings = Map.insert v (env,expr,i+1) (recursiveBindings env)})
(go expr)
else pure $ f 0
go (Let v e' e) = mdo
a <- local (\env -> let env' = env {recursiveBindings = Map.insert v (env',e',0) (recursiveBindings env) } in env')
(go e')
local (\e -> e {bindings = Map.insert v a (bindings e) })
(go e)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment