1
1
mirror of https://github.com/github/semantic.git synced 2025-01-03 13:02:37 +03:00

Express Evaluatable as an R-algebra.

Co-Authored-By: Josh Vera <vera@github.com>
This commit is contained in:
Rob Rix 2018-02-26 17:07:24 -05:00
parent ca21d42399
commit a99f97854d
6 changed files with 37 additions and 43 deletions

View File

@ -14,7 +14,6 @@ import Data.Abstract.Value
import Data.Abstract.FreeVariables import Data.Abstract.FreeVariables
import Data.Blob import Data.Blob
import Data.Traversable import Data.Traversable
import Data.Function (fix)
import Data.Functor.Foldable (Base, Recursive(..)) import Data.Functor.Foldable (Base, Recursive(..))
import Data.Foldable (toList) import Data.Foldable (toList)
import Data.Semigroup import Data.Semigroup
@ -53,7 +52,7 @@ require term = do
where where
evalModule linker name = case linkerLookupTerm name linker of evalModule linker name = case linkerLookupTerm name linker of
Just m -> do Just m -> do
v <- step @v m v <- para eval m
modify @(Linker term v) (linkerInsert name v) modify @(Linker term v) (linkerInsert name v)
trace ("require[eval]:" <> name) (pure v) trace ("require[eval]:" <> name) (pure v)
_ -> fail ("cannot find " <> show name) _ -> fail ("cannot find " <> show name)
@ -67,7 +66,7 @@ evaluate :: forall v term.
) )
=> term => term
-> Final (Evaluating term v) v -> Final (Evaluating term v) v
evaluate = run @(Evaluating term v) . fix (const step) evaluate = run @(Evaluating term v) . para eval
-- | Evaluate terms and an entry point to a value. -- | Evaluate terms and an entry point to a value.
evaluates :: forall v term. evaluates :: forall v term.
@ -79,11 +78,10 @@ evaluates :: forall v term.
=> [(Blob, term)] -- List of (blob, term) pairs that make up the program to be evaluated => [(Blob, term)] -- List of (blob, term) pairs that make up the program to be evaluated
-> (Blob, term) -- Entrypoint -> (Blob, term) -- Entrypoint
-> Final (Evaluating term v) v -> Final (Evaluating term v) v
evaluates pairs = run @(Evaluating term v) . fix go evaluates pairs (Blob{..}, t) = run @(Evaluating term v) $ do
where
go _ (Blob{..}, t) = do
put (Linker @term @v Map.empty (Map.fromList (fmap toPathActionPair pairs))) put (Linker @term @v Map.empty (Map.fromList (fmap toPathActionPair pairs)))
trace ("step[entryPoint]: " <> show blobPath) (step @v t) trace ("step[entryPoint]: " <> show blobPath) (para eval t)
where
toPathActionPair (Blob{..}, t) = (dropExtensions blobPath, t) toPathActionPair (Blob{..}, t) = (dropExtensions blobPath, t)
@ -120,7 +118,7 @@ evaluate' :: forall v term.
) )
=> term => term
-> Final (Evaluating' v) v -> Final (Evaluating' v) v
evaluate' = run @(Evaluating' v) . fix (const step) evaluate' = run @(Evaluating' v) . para eval
-- | Evaluate terms and an entry point to a value. -- | Evaluate terms and an entry point to a value.
evaluates' :: forall v term. evaluates' :: forall v term.
@ -132,14 +130,11 @@ evaluates' :: forall v term.
=> [(Blob, term)] -- List of (blob, term) pairs that make up the program to be evaluated => [(Blob, term)] -- List of (blob, term) pairs that make up the program to be evaluated
-> (Blob, term) -- Entrypoint -> (Blob, term) -- Entrypoint
-> Final (Evaluating' v) v -> Final (Evaluating' v) v
evaluates' pairs = run @(Evaluating' v) . fix go evaluates' pairs (Blob{..}, t) = run @(Evaluating' v) $ do
where
go _ (Blob{..}, t) = do
modules <- for pairs $ \(Blob{..}, t) -> do modules <- for pairs $ \(Blob{..}, t) -> do
v <- trace ("step: " <> show blobPath) $ step @v t v <- trace ("step: " <> show blobPath) $ para eval t
pure (dropExtensions blobPath, v) pure (dropExtensions blobPath, v :: v)
local (const (Linker' (Map.fromList modules))) (trace ("step: " <> show blobPath) (step @v t)) local (const (Linker' (Map.fromList modules))) (trace ("step: " <> show blobPath) (para eval t))
-- | The effects necessary for concrete interpretation. -- | The effects necessary for concrete interpretation.
-- --
@ -175,7 +170,7 @@ evaluate'' :: forall v term.
) )
=> term => term
-> Final (Evaluating'' v) v -> Final (Evaluating'' v) v
evaluate'' = run @(Evaluating'' v) . fix (const step) evaluate'' = run @(Evaluating'' v) . para eval
-- | Evaluate terms and an entry point to a value. -- | Evaluate terms and an entry point to a value.
evaluates'' :: forall v term. evaluates'' :: forall v term.
@ -187,10 +182,9 @@ evaluates'' :: forall v term.
=> [(Blob, term)] -- List of (blob, term) pairs that make up the program to be evaluated => [(Blob, term)] -- List of (blob, term) pairs that make up the program to be evaluated
-> (Blob, term) -- Entrypoint -> (Blob, term) -- Entrypoint
-> Final (Evaluating'' v) v -> Final (Evaluating'' v) v
evaluates'' pairs = run @(Evaluating'' v) . fix go evaluates'' pairs (Blob{..}, t) = run @(Evaluating'' v) $ local @(Linker' (Evaluator v)) (const (Linker' (Map.fromList (map toPathActionPair pairs)))) (trace ("step: " <> show blobPath) (para eval t))
where where
go _ (Blob{..}, t) = local (const (Linker' (Map.fromList (map toPathActionPair pairs)))) (trace ("step: " <> show blobPath) (step @v t)) toPathActionPair (Blob{..}, t) = (dropExtensions blobPath, Evaluator (para eval t))
toPathActionPair (Blob{..}, t) = (dropExtensions blobPath, Evaluator (step @v t))
-- | The effects necessary for concrete interpretation. -- | The effects necessary for concrete interpretation.

View File

@ -25,8 +25,8 @@ import qualified Data.Union as U
-- | The 'Evaluatable' class defines the necessary interface for a term to be evaluated. While a default definition of 'eval' is given, instances with computational content must implement 'eval' to perform their small-step operational semantics. -- | The 'Evaluatable' class defines the necessary interface for a term to be evaluated. While a default definition of 'eval' is given, instances with computational content must implement 'eval' to perform their small-step operational semantics.
class Evaluatable es term v constr where class Evaluatable es term v constr where
eval :: constr term -> Eff es v eval :: constr (term, Eff es v) -> Eff es v
default eval :: (Fail :< es, Show1 constr) => (constr term -> Eff es v) default eval :: (Fail :< es, Show1 constr) => (constr (term, Eff es v) -> Eff es v)
eval expr = fail $ "Eval unspecialized for " ++ liftShowsPrec (const (const id)) (const id) 0 expr "" eval expr = fail $ "Eval unspecialized for " ++ liftShowsPrec (const (const id)) (const id) 0 expr ""
-- | If we can evaluate any syntax which can occur in a 'Union', we can evaluate the 'Union'. -- | If we can evaluate any syntax which can occur in a 'Union', we can evaluate the 'Union'.
@ -38,9 +38,9 @@ instance (Evaluatable es t v s) => Evaluatable es t v (TermF s a) where
eval In{..} = eval termFOut eval In{..} = eval termFOut
-- | Evaluate by first projecting a term to recurse one level. -- | Evaluate by first projecting a term to recurse one level.
step :: forall v term es. (Evaluatable es term v (Base term), Recursive term) step :: Recursive term
=> term -> Eff es v => (term, Eff es v) -> Eff es v
step = eval . project step = snd
-- Instances -- Instances
@ -61,9 +61,9 @@ instance ( Ord (LocationFor v)
) )
=> Evaluatable es t v [] where => Evaluatable es t v [] where
eval [] = pure unit -- Return unit value if this is an empty list of terms eval [] = pure unit -- Return unit value if this is an empty list of terms
eval [x] = step x -- Return the value for the last term eval [(_, x)] = x -- Return the value for the last term
eval (x:xs) = do eval ((_, x):xs) = do
_ <- step @v x -- Evaluate the head term _ <- x -- Evaluate the head term
env <- get @(EnvironmentFor v) -- Get the global environment after evaluation env <- get @(EnvironmentFor v) -- Get the global environment after evaluation
-- since it might have been modified by the -- since it might have been modified by the
-- 'step' evaluation above ^. -- 'step' evaluation above ^.
@ -71,4 +71,4 @@ instance ( Ord (LocationFor v)
-- Finally, evaluate the rest of the terms, but do so by calculating a new -- Finally, evaluate the rest of the terms, but do so by calculating a new
-- environment each time where the free variables in those terms are bound -- environment each time where the free variables in those terms are bound
-- to the global environment. -- to the global environment.
local (const (bindEnv (freeVariables1 xs) env)) (eval xs) local (const (bindEnv (liftFreeVariables (freeVariables . fst) xs) env)) (eval xs)

View File

@ -163,9 +163,9 @@ instance ( Ord (LocationFor (Value l t))
interface val = inj . Value.Interface val <$> ask @(EnvironmentFor (Value l t)) interface val = inj . Value.Interface val <$> ask @(EnvironmentFor (Value l t))
eval' [] = interface unit eval' [] = interface unit
eval' [x] = step x >>= interface eval' [(_, x)] = x >>= interface
eval' (x:xs) = do eval' ((_, x):xs) = do
_ <- step @(Value l t) x _ <- x
env <- get @(EnvironmentFor (Value l t)) env <- get @(EnvironmentFor (Value l t))
local (envUnion env) (eval' xs) local (envUnion env) (eval' xs)

View File

@ -48,10 +48,10 @@ instance ( FreeVariables t
) => Evaluatable es t (Value l t) Function where ) => Evaluatable es t (Value l t) Function where
eval Function{..} = do eval Function{..} = do
env <- ask env <- ask
let params = toList (freeVariables1 functionParameters) let params = toList (liftFreeVariables (freeVariables . fst) functionParameters)
let v = inj (Closure params functionBody env) :: Value l t let v = inj (Closure params (fst functionBody) env) :: Value l t
(name, addr) <- lookupOrAlloc functionName v env (name, addr) <- lookupOrAlloc (fst functionName) v env
modify (envInsert name addr) modify (envInsert name addr)
pure v pure v
@ -104,10 +104,10 @@ instance ( FreeVariables t -- To get free variables from the func
) => Evaluatable es t (Value l t) Method where ) => Evaluatable es t (Value l t) Method where
eval Method{..} = do eval Method{..} = do
env <- ask env <- ask
let params = toList (freeVariables1 methodParameters) let params = toList (liftFreeVariables (freeVariables . fst) methodParameters)
let v = inj (Closure params methodBody env) :: Value l t let v = inj (Closure params (fst methodBody) env) :: Value l t
(name, addr) <- lookupOrAlloc methodName v env (name, addr) <- lookupOrAlloc (fst methodName) v env
modify (envInsert name addr) modify (envInsert name addr)
pure v pure v
@ -286,7 +286,7 @@ instance ( Show l
, FreeVariables t , FreeVariables t
) )
=> Evaluatable es t (Value l t) Import where => Evaluatable es t (Value l t) Import where
eval (Import from _ _) = do eval (Import (from, _) _ _) = do
interface <- require @(Value l t) @t from interface <- require @(Value l t) @t from
-- TODO: Consider returning the value instead of the interface. -- TODO: Consider returning the value instead of the interface.
Interface _ env <- maybe Interface _ env <- maybe

View File

@ -43,7 +43,7 @@ instance ( Ord l
, Recursive t , Recursive t
) => Evaluatable es t (Value l t) Call where ) => Evaluatable es t (Value l t) Call where
eval Call{..} = do eval Call{..} = do
closure <- step @(Value l t) callFunction closure <- step callFunction
Closure names body env <- maybe (fail "expected a closure") pure (prj closure :: Maybe (Closure l t)) Closure names body env <- maybe (fail "expected a closure") pure (prj closure :: Maybe (Closure l t))
bindings <- for (zip names callParams) $ \(name, param) -> do bindings <- for (zip names callParams) $ \(name, param) -> do
v <- step param v <- step param
@ -51,7 +51,7 @@ instance ( Ord l
assign a v assign a v
pure (name, a) pure (name, a)
local (const (foldr (uncurry envInsert) env bindings)) (step body) local (const (foldr (uncurry envInsert) env bindings)) (para eval body)
-- TODO: Implement type checking for Call -- TODO: Implement type checking for Call
instance Member Fail es => Evaluatable es t Type.Type Call instance Member Fail es => Evaluatable es t Type.Type Call

View File

@ -114,7 +114,7 @@ instance ( Semigroup (Cell (LocationFor v) v)
=> Evaluatable es t v Assignment where => Evaluatable es t v Assignment where
eval Assignment{..} = do eval Assignment{..} = do
v <- step assignmentValue v <- step assignmentValue
(var, a) <- ask >>= lookupOrAlloc assignmentTarget v (var, a) <- ask >>= lookupOrAlloc (fst assignmentTarget) v
modify (envInsert var a) modify (envInsert var a)
pure v pure v