mirror of
https://github.com/GrammaticalFramework/gf-core.git
synced 2026-04-23 19:42:50 -06:00
Predef combinators
This commit is contained in:
@@ -1,11 +1,13 @@
|
|||||||
{-# LANGUAGE RankNTypes, BangPatterns, CPP, ExistentialQuantification #-}
|
{-# LANGUAGE RankNTypes, BangPatterns, CPP, ExistentialQuantification, LambdaCase #-}
|
||||||
|
|
||||||
-- | Functions for computing the values of terms in the concrete syntax, in
|
-- | Functions for computing the values of terms in the concrete syntax, in
|
||||||
-- | preparation for PMCFG generation.
|
-- | preparation for PMCFG generation.
|
||||||
module GF.Compile.Compute.Concrete
|
module GF.Compile.Compute.Concrete
|
||||||
( normalForm, normalFlatForm, normalStringForm
|
( normalForm, normalFlatForm, normalStringForm
|
||||||
, Value(..), Thunk, ThunkState(..), Env, Scope, showValue
|
, Value(..), Thunk, ThunkState(..), Env, Scope, showValue
|
||||||
, MetaThunks, Constraint, Globals(..), ConstValue(..)
|
, PredefImpl, Predef(..), PredefCombinator, ($\)
|
||||||
|
, pdForce, pdClosedArgs, pdArity, pdStandard
|
||||||
|
, MetaThunks, Constraint, PredefTable, Globals(..), ConstValue(..)
|
||||||
, EvalM(..), runEvalM, runEvalOneM, reset, evalError, evalWarn
|
, EvalM(..), runEvalM, runEvalOneM, reset, evalError, evalWarn
|
||||||
, eval, apply, force, value2term, patternMatch, stdPredef
|
, eval, apply, force, value2term, patternMatch, stdPredef
|
||||||
, unsafeIOToEvalM
|
, unsafeIOToEvalM
|
||||||
@@ -26,7 +28,7 @@ import GF.Grammar.Predef
|
|||||||
import GF.Grammar.Lockfield(lockLabel)
|
import GF.Grammar.Lockfield(lockLabel)
|
||||||
import GF.Grammar.Printer
|
import GF.Grammar.Printer
|
||||||
import GF.Data.Operations(Err(..))
|
import GF.Data.Operations(Err(..))
|
||||||
import GF.Data.Utilities((<||>),anyM)
|
import GF.Data.Utilities(splitAt',(<||>),anyM)
|
||||||
import GF.Infra.CheckM
|
import GF.Infra.CheckM
|
||||||
import GF.Infra.Option
|
import GF.Infra.Option
|
||||||
import Data.STRef
|
import Data.STRef
|
||||||
@@ -238,15 +240,12 @@ eval env (S t1 t2) vs = do v1 <- eval env t1 []
|
|||||||
v1 -> return v0
|
v1 -> return v0
|
||||||
eval env (Let (x,(_,t1)) t2) vs = do tnk <- newThunk env t1
|
eval env (Let (x,(_,t1)) t2) vs = do tnk <- newThunk env t1
|
||||||
eval ((x,tnk):env) t2 vs
|
eval ((x,tnk):env) t2 vs
|
||||||
eval env (Q q@(m,id)) vs
|
eval env t@(Q q@(m,id)) vs
|
||||||
| m == cPredef = do vs' <- mapM force vs -- FIXME this does not allow for partial application!
|
| m == cPredef = do res <- evalPredef env t id vs
|
||||||
open <- anyM (value2term True [] >=> isOpen []) vs'
|
case res of
|
||||||
if open then return (VApp q vs) else do
|
Const res -> return res
|
||||||
res <- evalPredef id vs'
|
RunTime -> return (VApp q vs)
|
||||||
case res of
|
NonExist -> return (VApp (cPredef,cNonExist) [])
|
||||||
Const res -> return res
|
|
||||||
RunTime -> return (VApp q vs)
|
|
||||||
NonExist -> return (VApp (cPredef,cNonExist) [])
|
|
||||||
| otherwise = do t <- getResDef q
|
| otherwise = do t <- getResDef q
|
||||||
eval env t vs
|
eval env t vs
|
||||||
eval env (QC q) vs = return (VApp q vs)
|
eval env (QC q) vs = return (VApp q vs)
|
||||||
@@ -326,25 +325,25 @@ apply (VClosure env (Abs b x t)) (v:vs) = eval ((x,v):env) t vs
|
|||||||
apply v [] = return v
|
apply v [] = return v
|
||||||
|
|
||||||
|
|
||||||
stdPredef :: Map.Map Ident ([Value s] -> EvalM s (ConstValue (Value s)))
|
stdPredef :: PredefTable s
|
||||||
stdPredef = Map.fromList
|
stdPredef = Map.fromList
|
||||||
[(cLength, \[v] -> case value2string v of
|
[(cLength, pdStandard 1 $\ \[v] -> case value2string v of
|
||||||
Const s -> return (Const (VInt (genericLength s)))
|
Const s -> return (Const (VInt (genericLength s)))
|
||||||
_ -> return RunTime)
|
_ -> return RunTime)
|
||||||
,(cTake, \[v1,v2] -> return (fmap string2value (liftA2 genericTake (value2int v1) (value2string v2))))
|
,(cTake, pdStandard 2 $\ \[v1,v2] -> return (fmap string2value (liftA2 genericTake (value2int v1) (value2string v2))))
|
||||||
,(cDrop, \[v1,v2] -> return (fmap string2value (liftA2 genericDrop (value2int v1) (value2string v2))))
|
,(cDrop, pdStandard 2 $\ \[v1,v2] -> return (fmap string2value (liftA2 genericDrop (value2int v1) (value2string v2))))
|
||||||
,(cTk, \[v1,v2] -> return (fmap string2value (liftA2 genericTk (value2int v1) (value2string v2))))
|
,(cTk, pdStandard 2 $\ \[v1,v2] -> return (fmap string2value (liftA2 genericTk (value2int v1) (value2string v2))))
|
||||||
,(cDp, \[v1,v2] -> return (fmap string2value (liftA2 genericDp (value2int v1) (value2string v2))))
|
,(cDp, pdStandard 2 $\ \[v1,v2] -> return (fmap string2value (liftA2 genericDp (value2int v1) (value2string v2))))
|
||||||
,(cIsUpper,\[v] -> return (fmap toPBool (liftA (all isUpper) (value2string v))))
|
,(cIsUpper,pdStandard 1 $\ \[v] -> return (fmap toPBool (liftA (all isUpper) (value2string v))))
|
||||||
,(cToUpper,\[v] -> return (fmap string2value (liftA (map toUpper) (value2string v))))
|
,(cToUpper,pdStandard 1 $\ \[v] -> return (fmap string2value (liftA (map toUpper) (value2string v))))
|
||||||
,(cToLower,\[v] -> return (fmap string2value (liftA (map toLower) (value2string v))))
|
,(cToLower,pdStandard 1 $\ \[v] -> return (fmap string2value (liftA (map toLower) (value2string v))))
|
||||||
,(cEqStr, \[v1,v2] -> return (fmap toPBool (liftA2 (==) (value2string v1) (value2string v2))))
|
,(cEqStr, pdStandard 2 $\ \[v1,v2] -> return (fmap toPBool (liftA2 (==) (value2string v1) (value2string v2))))
|
||||||
,(cOccur, \[v1,v2] -> return (fmap toPBool (liftA2 occur (value2string v1) (value2string v2))))
|
,(cOccur, pdStandard 2 $\ \[v1,v2] -> return (fmap toPBool (liftA2 occur (value2string v1) (value2string v2))))
|
||||||
,(cOccurs, \[v1,v2] -> return (fmap toPBool (liftA2 occurs (value2string v1) (value2string v2))))
|
,(cOccurs, pdStandard 2 $\ \[v1,v2] -> return (fmap toPBool (liftA2 occurs (value2string v1) (value2string v2))))
|
||||||
,(cEqInt, \[v1,v2] -> return (fmap toPBool (liftA2 (==) (value2int v1) (value2int v2))))
|
,(cEqInt, pdStandard 2 $\ \[v1,v2] -> return (fmap toPBool (liftA2 (==) (value2int v1) (value2int v2))))
|
||||||
,(cLessInt,\[v1,v2] -> return (fmap toPBool (liftA2 (<) (value2int v1) (value2int v2))))
|
,(cLessInt,pdStandard 2 $\ \[v1,v2] -> return (fmap toPBool (liftA2 (<) (value2int v1) (value2int v2))))
|
||||||
,(cPlus, \[v1,v2] -> return (fmap VInt (liftA2 (+) (value2int v1) (value2int v2))))
|
,(cPlus, pdStandard 2 $\ \[v1,v2] -> return (fmap VInt (liftA2 (+) (value2int v1) (value2int v2))))
|
||||||
,(cError, \[v] -> case value2string v of
|
,(cError, pdStandard 1 $\ \[v] -> case value2string v of
|
||||||
Const msg -> fail msg
|
Const msg -> fail msg
|
||||||
_ -> fail "Indescribable error appeared")
|
_ -> fail "Indescribable error appeared")
|
||||||
]
|
]
|
||||||
@@ -705,6 +704,16 @@ instance Applicative ConstValue where
|
|||||||
liftA2 f _ RunTime = RunTime
|
liftA2 f _ RunTime = RunTime
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
instance Foldable ConstValue where
|
||||||
|
foldr f a (Const x) = f x a
|
||||||
|
foldr f a RunTime = a
|
||||||
|
foldr f a NonExist = a
|
||||||
|
|
||||||
|
instance Traversable ConstValue where
|
||||||
|
traverse f (Const x) = Const <$> f x
|
||||||
|
traverse f RunTime = pure RunTime
|
||||||
|
traverse f NonExist = pure NonExist
|
||||||
|
|
||||||
value2string v = fmap (\(_,ws,_) -> unwords ws) (value2string' v False [] [])
|
value2string v = fmap (\(_,ws,_) -> unwords ws) (value2string' v False [] [])
|
||||||
|
|
||||||
value2string' (VStr w1) True (w2:ws) qs = Const (False,(w1++w2):ws,qs)
|
value2string' (VStr w1) True (w2:ws) qs = Const (False,(w1++w2):ws,qs)
|
||||||
@@ -762,12 +771,63 @@ string2value' (w:ws) = VC (VStr w) (string2value' ws)
|
|||||||
value2int (VInt n) = Const n
|
value2int (VInt n) = Const n
|
||||||
value2int _ = RunTime
|
value2int _ = RunTime
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
-- * Global/built-in definitions
|
||||||
|
|
||||||
|
type PredefImpl a s = [a] -> EvalM s (ConstValue (Value s))
|
||||||
|
newtype Predef a s = Predef { runPredef :: Term -> Env s -> PredefImpl a s }
|
||||||
|
type PredefCombinator a b s = Predef a s -> Predef b s
|
||||||
|
|
||||||
|
infix 0 $\\
|
||||||
|
|
||||||
|
($\) :: PredefCombinator a b s -> PredefImpl a s -> Predef b s
|
||||||
|
k $\ f = k (Predef (\_ _ -> f))
|
||||||
|
|
||||||
|
pdForce :: PredefCombinator (Value s) (Thunk s) s
|
||||||
|
pdForce def = Predef $ \h env args -> do
|
||||||
|
argValues <- mapM force args
|
||||||
|
runPredef def h env argValues
|
||||||
|
|
||||||
|
pdClosedArgs :: PredefCombinator (Value s) (Value s) s
|
||||||
|
pdClosedArgs def = Predef $ \h env args -> do
|
||||||
|
open <- anyM (value2term True [] >=> isOpen []) args
|
||||||
|
if open then return RunTime else runPredef def h env args
|
||||||
|
|
||||||
|
pdArity :: Int -> PredefCombinator (Thunk s) (Thunk s) s
|
||||||
|
pdArity n def = Predef $ \h env args ->
|
||||||
|
case splitAt' n args of
|
||||||
|
Nothing -> do
|
||||||
|
t <- papply env h args
|
||||||
|
let t' = abstract 0 (n - length args) t
|
||||||
|
Const <$> eval env t' []
|
||||||
|
Just (usedArgs, remArgs) -> do
|
||||||
|
res <- runPredef def h env usedArgs
|
||||||
|
forM res $ \v -> case remArgs of
|
||||||
|
[] -> return v
|
||||||
|
_ -> do
|
||||||
|
t <- value2term False (fst <$> env) v
|
||||||
|
eval env t remArgs
|
||||||
|
where
|
||||||
|
papply env t [] = return t
|
||||||
|
papply env t (arg:args) = do
|
||||||
|
arg <- tnk2term False (fst <$> env) arg
|
||||||
|
papply env (App t arg) args
|
||||||
|
|
||||||
|
abstract i n t
|
||||||
|
| n <= 0 = t
|
||||||
|
| otherwise = let x = identV (rawIdentS "a") i
|
||||||
|
in Abs Explicit x (abstract (i + 1) (n - 1) (App t (Vr x)))
|
||||||
|
|
||||||
|
pdStandard :: Int -> PredefCombinator (Value s) (Thunk s) s
|
||||||
|
pdStandard n = pdArity n . pdForce . pdClosedArgs
|
||||||
|
|
||||||
-----------------------------------------------------------------------
|
-----------------------------------------------------------------------
|
||||||
-- * Evaluation monad
|
-- * Evaluation monad
|
||||||
|
|
||||||
type MetaThunks s = Map.Map MetaId (Thunk s)
|
type MetaThunks s = Map.Map MetaId (Thunk s)
|
||||||
type Cont s r = MetaThunks s -> Int -> r -> [Message] -> ST s (CheckResult r [Message])
|
type Cont s r = MetaThunks s -> Int -> r -> [Message] -> ST s (CheckResult r [Message])
|
||||||
data Globals = Gl Grammar (forall s . Map.Map Ident ([Value s] -> EvalM s (ConstValue (Value s))))
|
type PredefTable s = Map.Map Ident (Predef (Thunk s) s)
|
||||||
|
data Globals = Gl Grammar (forall s . PredefTable s)
|
||||||
newtype EvalM s a = EvalM (forall r . Globals -> (a -> Cont s r) -> Cont s r)
|
newtype EvalM s a = EvalM (forall r . Globals -> (a -> Cont s r) -> Cont s r)
|
||||||
|
|
||||||
instance Functor (EvalM s) where
|
instance Functor (EvalM s) where
|
||||||
@@ -826,9 +886,9 @@ evalError msg = EvalM (\gr k _ _ r msgs -> return (Fail msg msgs))
|
|||||||
evalWarn :: Message -> EvalM s ()
|
evalWarn :: Message -> EvalM s ()
|
||||||
evalWarn msg = EvalM (\gr k mt d r msgs -> k () mt d r (msg:msgs))
|
evalWarn msg = EvalM (\gr k mt d r msgs -> k () mt d r (msg:msgs))
|
||||||
|
|
||||||
evalPredef :: Ident -> [Value s] -> EvalM s (ConstValue (Value s))
|
evalPredef :: Env s -> Term -> Ident -> [Thunk s] -> EvalM s (ConstValue (Value s))
|
||||||
evalPredef id vs = EvalM (\globals@(Gl _ predef) k mt d r msgs ->
|
evalPredef env h id args = EvalM (\globals@(Gl _ predef) k mt d r msgs ->
|
||||||
case fmap (\f -> f vs) (Map.lookup id predef) of
|
case fmap (\def -> runPredef def h env args) (Map.lookup id predef) of
|
||||||
Just (EvalM f) -> f globals k mt d r msgs
|
Just (EvalM f) -> f globals k mt d r msgs
|
||||||
Nothing -> k RunTime mt d r msgs)
|
Nothing -> k RunTime mt d r msgs)
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
module GF.Data.Utilities(module GF.Data.Utilities) where
|
module GF.Data.Utilities(module GF.Data.Utilities) where
|
||||||
|
|
||||||
|
import Data.Bifunctor (first)
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.List
|
import Data.List
|
||||||
import Control.Monad (MonadPlus(..),foldM,liftM,when)
|
import Control.Monad (MonadPlus(..),foldM,liftM,when)
|
||||||
@@ -45,6 +46,14 @@ splitBy p [] = ([], [])
|
|||||||
splitBy p (a : as) = if p a then (a:xs, ys) else (xs, a:ys)
|
splitBy p (a : as) = if p a then (a:xs, ys) else (xs, a:ys)
|
||||||
where (xs, ys) = splitBy p as
|
where (xs, ys) = splitBy p as
|
||||||
|
|
||||||
|
splitAt' :: Int -> [a] -> Maybe ([a], [a])
|
||||||
|
splitAt' n xs
|
||||||
|
| n <= 0 = Just ([], xs)
|
||||||
|
| otherwise = helper n xs
|
||||||
|
where helper 0 xs = Just ([], xs)
|
||||||
|
helper n [] = Nothing
|
||||||
|
helper n (x:xs) = first (x:) <$> helper (n - 1) xs
|
||||||
|
|
||||||
foldMerge :: (a -> a -> a) -> a -> [a] -> a
|
foldMerge :: (a -> a -> a) -> a -> [a] -> a
|
||||||
foldMerge merge zero = fm
|
foldMerge merge zero = fm
|
||||||
where fm [] = zero
|
where fm [] = zero
|
||||||
|
|||||||
Reference in New Issue
Block a user