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:
parent
ca21d42399
commit
a99f97854d
@ -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.
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user