summaryrefslogtreecommitdiff
path: root/source/Felix/Meaning.hs
diff options
context:
space:
mode:
Diffstat (limited to 'source/Felix/Meaning.hs')
-rw-r--r--source/Felix/Meaning.hs1770
1 files changed, 1770 insertions, 0 deletions
diff --git a/source/Felix/Meaning.hs b/source/Felix/Meaning.hs
new file mode 100644
index 0000000..268a1a6
--- /dev/null
+++ b/source/Felix/Meaning.hs
@@ -0,0 +1,1770 @@
+{-# LANGUAGE ApplicativeDo #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE MultiWayIf #-}
+{-# LANGUAGE TupleSections #-}
+
+
+module Felix.Meaning where
+
+
+import Base
+import Felix.Syntax.Abstract (Sign(..))
+import Felix.Syntax.Abstract qualified as Raw
+import Felix.Syntax.Internal (VarSymbol(..), pattern FreshVar)
+import Felix.Syntax.Internal qualified as Sem
+import Felix.Syntax.LexicalPhrase (unsafeReadPhrase)
+import Felix.Report.Location
+
+import Bound
+import Control.Monad.Except
+import Control.Monad.State
+import Data.List qualified as List
+import Data.List.NonEmpty qualified as NonEmpty
+import Data.Map qualified as Map
+import Data.Set qualified as Set
+import Control.Exception (Exception)
+
+
+-- | The 'Gloss' monad. Basic elaboration, desugaring, and validation
+-- computations take place in this monad, using 'ExceptT' to log
+-- validation errors and 'State' to keep track of the surrounding context.
+type Gloss = ExceptT GlossError (State GlossState)
+-- This monad previously used 'ValidationT' for validation so that multiple
+-- validation errors could be reported. Using only 'ExceptT' we fail immediately
+-- on the first error. If we ever swich back to 'ValidateT' for error reporting,
+-- then we should re-enable {-# OPTIONS_GHC -foptimal-applicative-do #-},
+-- as 'ValidateT' can report more errors when used with applicative combinators.
+
+-- These types are a private bridge to the current VarSymbol-based core.
+newtype LocalId = LocalId Int
+ deriving (Show, Eq, Ord)
+
+data BinderTrivia = BinderTrivia
+ { binderDisplayHint :: Maybe Text
+ , binderDeclarationLocation :: Location
+ } deriving (Show, Eq, Ord)
+
+data ResolvedLocalRef
+ = AmbientRef VarSymbol
+ | LocalRef LocalId
+ deriving (Show, Eq, Ord)
+
+data H0ResolvedBinder = H0ResolvedBinder
+ { h0BinderId :: LocalId
+ , h0BinderTrivia :: BinderTrivia
+ } deriving (Show, Eq, Ord)
+
+data ResolvedBinderAdapterError
+ = UnknownResolvedLocal LocalId
+ | DuplicateResolvedLocalAssignment LocalId
+ | ResolvedLocalTokenCollision LocalId VarSymbol
+ deriving (Show, Eq, Ord)
+
+-- | Errors that can be detected during glossing.
+data GlossError
+ = GlossDefnError Location DefnError Sem.Marker
+ | GlossInductionError Location
+ | GlossRelationExprWithParams Location
+ | GlossRelationApplicationError Sem.RelationApplicationError
+ | GlossDatatypeHeadError Location
+ | GlossDatatypeClauseTargetError Location
+ | GlossDatatypeConstructorError Location
+ | DependentReplacementDomainNotSupported Location
+ | QuantifiedTermRequiresResolvedContext Location
+ | IotaTermNotSupported Location
+ | DefiniteFunctionAssumptionNotSupported Location
+ | GlossProofFunctionArgumentMismatch
+ Location
+ VarSymbol
+ VarSymbol
+ | GlossProofFunctionNameMismatch
+ Location
+ VarSymbol
+ VarSymbol
+ | GlossAbbreviationError
+ Location
+ Sem.Marker
+ AbbreviationParameterError
+ | DuplicateQuantifiedNounBinder
+ Location
+ Location
+ Text
+ | GlossResolvedBinderAdapterError
+ Location
+ ResolvedBinderAdapterError
+ deriving (Eq, Ord)
+
+data AbbreviationParameterError
+ = DuplicateAbbreviationParameters (NonEmpty VarSymbol)
+ | FreeAbbreviationBodyVariables (NonEmpty VarSymbol)
+ deriving (Show, Eq, Ord)
+
+instance Exception GlossError
+instance Show GlossError where show = explainGlossError
+
+explainGlossError :: GlossError -> String
+explainGlossError = \case
+ GlossDefnError loc defnError marker ->
+ "Definition error at " <> prettyLocation loc <> " (in " <> show marker <> "): " <> case defnError of
+ DefnWarnLhsFree xs ->
+ "The variables " <> show xs <> " in the pattern being defined (definiendum) do not occur in the body of the definition (definiens). Remove them or use them in the body."
+ DefnErrorLhsNotLinear ->
+ "The left-hand side of the definition is not linear (a variable occurs multiple times)."
+ DefnErrorLhsTypeFree ->
+ "The defintion contains variables with no typing constraints or assumptions placed on them."
+ DefnErrorRhsFree xs ->
+ "The variables " <> show xs <> " on the right-hand side of the definition do not occurring on the left-hand side."
+ DefnErrorQuantifiedRhsTerm ->
+ "A quantified term cannot be the right-hand side of a functional definition."
+ GlossInductionError loc ->
+ "Error at " <> prettyLocation loc <> ": Induction over a non-variable is not supported."
+ GlossRelationExprWithParams loc ->
+ "Error at " <> prettyLocation loc <> ": A relation defined by an expression cannot have parameters."
+ GlossRelationApplicationError
+ (Sem.RelationParameterArityMismatch loc relation expected actual) ->
+ "Relation "
+ <> show (Sem.relationSymbolToken relation)
+ <> " at "
+ <> prettyLocation loc
+ <> " expects "
+ <> show (Sem.parameterArityValue expected)
+ <> " parameter(s), but received "
+ <> show (Sem.parameterArityValue actual)
+ <> "."
+ GlossDatatypeHeadError loc ->
+ "Error at " <> prettyLocation loc <> ": A datatype head must be a constant symbolic term."
+ GlossDatatypeClauseTargetError loc ->
+ "Error at " <> prettyLocation loc <> ": Every datatype clause must target the datatype being defined."
+ GlossDatatypeConstructorError loc ->
+ "Error at " <> prettyLocation loc <> ": Datatype constructors must be symbolic terms with bare variable arguments."
+ DependentReplacementDomainNotSupported loc ->
+ "Error at "
+ <> prettyLocation loc
+ <> ": dependent replacement domains are not yet supported."
+ QuantifiedTermRequiresResolvedContext loc ->
+ "Error at "
+ <> prettyLocation loc
+ <> ": a quantified term requires a resolved binding context."
+ IotaTermNotSupported loc ->
+ "Error at "
+ <> prettyLocation loc
+ <> ": definite-description terms are not supported."
+ DefiniteFunctionAssumptionNotSupported loc ->
+ "Error at "
+ <> prettyLocation loc
+ <> ": definite-function assumptions are not supported."
+ GlossProofFunctionArgumentMismatch loc valueArgument domainArgument ->
+ "Function definition error at "
+ <> prettyLocation loc
+ <> ": value argument "
+ <> show valueArgument
+ <> " does not match domain argument "
+ <> show domainArgument
+ <> "."
+ GlossProofFunctionNameMismatch loc declaredFunction definedFunction ->
+ "Function definition error at "
+ <> prettyLocation loc
+ <> ": declared function "
+ <> show declaredFunction
+ <> " does not match defined function "
+ <> show definedFunction
+ <> "."
+ GlossAbbreviationError loc marker abbreviationError ->
+ "Abbreviation error at "
+ <> prettyLocation loc
+ <> " (in "
+ <> show marker
+ <> "): "
+ <> case abbreviationError of
+ DuplicateAbbreviationParameters variables ->
+ "The parameters "
+ <> show (NonEmpty.toList variables)
+ <> " occur more than once."
+ FreeAbbreviationBodyVariables variables ->
+ "The body contains free variables not present in the head: "
+ <> show (NonEmpty.toList variables)
+ <> "."
+ DuplicateQuantifiedNounBinder firstLocation secondLocation name ->
+ "Quantified noun binder "
+ <> show name
+ <> " at "
+ <> prettyLocation secondLocation
+ <> " duplicates the overlapping binder at "
+ <> prettyLocation firstLocation
+ <> "."
+ GlossResolvedBinderAdapterError location adapterError ->
+ "Resolved binder adapter error at "
+ <> prettyLocation location
+ <> ": "
+ <> case adapterError of
+ UnknownResolvedLocal localId ->
+ "unknown local reference " <> show localId <> "."
+ DuplicateResolvedLocalAssignment localId ->
+ "duplicate legacy assignment for " <> show localId <> "."
+ ResolvedLocalTokenCollision localId token ->
+ "legacy token "
+ <> show token
+ <> " for "
+ <> show localId
+ <> " is not fresh."
+
+liftRelationApplication
+ :: Either Sem.RelationApplicationError a
+ -> Gloss a
+liftRelationApplication =
+ either (throwError . GlossRelationApplicationError) pure
+
+-- | Specialization of 'traverse' to 'Gloss'.
+each :: (Traversable t) => (a -> Gloss b) -> t a -> Gloss (t b)
+explain `each` as = traverse explain as
+infix 7 `each` -- In particular, 'each' has precedence over '(<$>)'.
+
+-- | Wellformedness check for definitions.
+-- The following conditions need to be met.
+--
+-- * Variables occurring in the lexical phrases on the left side must be linear,
+-- i.e. each variable can only occur once.
+-- * The arguments of the lexical phrases must be variables, not complex terms.
+-- This is statically guaranteed by the grammar.
+-- * The optional typing noun may not have any free variables.
+-- * The rhs side may not have any free variables not occurring on the lhs.
+-- * If a variable on the lhs does not occur on the rhs, a warning should we issued.
+--
+isWellformedDefn :: Sem.Defn -> Either DefnError Sem.Defn
+isWellformedDefn defn =
+ if | ls' /= ls -> Left DefnErrorLhsNotLinear
+ | not (null rdiff) -> Left (DefnErrorRhsFree (toList rdiff))
+ | not (null ldiff) -> case defn of
+ Sem.DefnPredicate{} -> Left (DefnWarnLhsFree (toList ldiff))
+ _ -> Right defn
+ | otherwise -> Right defn
+ where
+ ls = lhsVars defn
+ ls' = nubOrd ls
+ rs = rhsVars defn
+ (ldiff, rdiff) = symmetricDifferenceDecompose (Set.fromList ls') rs
+
+
+lhsVars :: Sem.Defn -> [VarSymbol]
+lhsVars = \case
+ Sem.DefnPredicate _ _ vs _ -> toList vs
+ Sem.DefnFun _ _ vs _ -> vs
+ Sem.DefnOp _ vs _ -> vs
+
+rhsVars :: Sem.Defn -> Set VarSymbol
+rhsVars = \case
+ Sem.DefnPredicate _ _ _ f -> Sem.freeVars f
+ Sem.DefnFun _ _ _ e -> Sem.freeVars e
+ Sem.DefnOp _ _ e -> Sem.freeVars e
+
+
+-- | Validation errors for top-level definitions.
+data DefnError
+ = DefnWarnLhsFree [VarSymbol]
+ | DefnErrorLhsNotLinear
+ | DefnErrorLhsTypeFree
+ | DefnErrorRhsFree [VarSymbol]
+ | DefnErrorQuantifiedRhsTerm
+ deriving (Show, Eq, Ord)
+
+
+-- | Context for 'Gloss' computations.
+data GlossState = GlossState
+ { varCount :: Int
+ -- ^ Counter for generating variables names for the output.
+ , localCount :: Int
+ -- ^ Counter for resolved quantified-noun binders.
+ , localBinderTrivia :: Map LocalId BinderTrivia
+ , legacyLocalTokens :: Map LocalId VarSymbol
+ } deriving (Show, Eq)
+
+freshVar :: Gloss VarSymbol
+freshVar = do
+ i <- gets varCount
+ modify $ \s -> s {varCount = varCount s + 1}
+ pure $ FreshVar i
+
+type H0LexicalEnvironment = [H0ResolvedBinder]
+
+type H0Expr = Sem.ExprOf ResolvedLocalRef
+
+freshH0Binder
+ :: Location
+ -> Maybe VarSymbol
+ -> Gloss H0ResolvedBinder
+freshH0Binder termLocation writtenName = do
+ nextLocal <- gets localCount
+ let localId = LocalId nextLocal
+ trivia = BinderTrivia
+ { binderDisplayHint = writtenName >>= displayedVariableName
+ , binderDeclarationLocation =
+ maybe termLocation locate writtenName
+ }
+ binder = H0ResolvedBinder localId trivia
+ modify \glossState ->
+ glossState
+ { localCount = nextLocal + 1
+ , localBinderTrivia =
+ Map.insert localId trivia (localBinderTrivia glossState)
+ }
+ pure binder
+ where
+ displayedVariableName = \case
+ NamedVarAt _ name -> Just name
+ FreshVarAt{} -> Nothing
+
+pushH0Binder
+ :: H0ResolvedBinder
+ -> H0LexicalEnvironment
+ -> H0LexicalEnvironment
+pushH0Binder = (:)
+
+resolveH0Reference
+ :: H0LexicalEnvironment
+ -> VarSymbol
+ -> ResolvedLocalRef
+resolveH0Reference environment variable = case variable of
+ NamedVarAt _ name ->
+ maybe
+ (AmbientRef variable)
+ (LocalRef . h0BinderId)
+ (List.find hasDisplayName environment)
+ where
+ hasDisplayName binder =
+ binderDisplayHint (h0BinderTrivia binder) == Just name
+ FreshVarAt{} ->
+ AmbientRef variable
+
+resolveH0Expr
+ :: H0LexicalEnvironment
+ -> Sem.Expr
+ -> H0Expr
+resolveH0Expr environment =
+ fmap (resolveH0Reference environment)
+
+lowerH0Expr :: H0Expr -> Gloss Sem.Expr
+lowerH0Expr =
+ traverse \case
+ AmbientRef variable ->
+ pure variable
+ LocalRef localId -> do
+ trivia <- gets (Map.lookup localId . localBinderTrivia)
+ throwError
+ (GlossResolvedBinderAdapterError
+ (maybe Nowhere binderDeclarationLocation trivia)
+ (UnknownResolvedLocal localId))
+
+abstractH0Binder
+ :: H0ResolvedBinder
+ -> H0Expr
+ -> Gloss (Scope VarSymbol Sem.ExprOf ResolvedLocalRef)
+abstractH0Binder binder body = do
+ token <- allocateLegacyLocalToken binder body
+ pure
+ (abstract
+ (\case
+ LocalRef localId
+ | localId == h0BinderId binder ->
+ Just token
+ _ ->
+ Nothing)
+ body)
+
+allocateLegacyLocalToken
+ :: H0ResolvedBinder
+ -> H0Expr
+ -> Gloss VarSymbol
+allocateLegacyLocalToken binder body = do
+ assignments <- gets legacyLocalTokens
+ case Map.lookup localId assignments of
+ Just _ ->
+ throwAdapterError
+ (DuplicateResolvedLocalAssignment localId)
+ Nothing -> do
+ let ambientTokens =
+ Set.fromList
+ [ token
+ | AmbientRef token <- toList body
+ ]
+ assignedTokens =
+ Set.fromList (Map.elems assignments)
+ forbiddenTokens =
+ ambientTokens <> assignedTokens
+ token <- freshTokenOutside forbiddenTokens
+ if token `Set.member` forbiddenTokens
+ then
+ throwAdapterError
+ (ResolvedLocalTokenCollision localId token)
+ else do
+ modify \glossState ->
+ glossState
+ { legacyLocalTokens =
+ Map.insert
+ localId
+ token
+ (legacyLocalTokens glossState)
+ }
+ pure token
+ where
+ localId = h0BinderId binder
+ binderLocation =
+ binderDeclarationLocation (h0BinderTrivia binder)
+ throwAdapterError =
+ throwError
+ . GlossResolvedBinderAdapterError binderLocation
+
+ freshTokenOutside forbidden = do
+ candidate <- freshVar
+ if candidate `Set.member` forbidden
+ then freshTokenOutside forbidden
+ else pure candidate
+
+initialGlossState :: GlossState
+initialGlossState = GlossState
+ { varCount = 0
+ , localCount = 0
+ , localBinderTrivia = mempty
+ , legacyLocalTokens = mempty
+ }
+
+glossStep :: GlossState -> Raw.Block -> Either GlossError (Sem.Block, GlossState)
+glossStep glossState block = case runState (runExceptT (glossBlock block)) glossState of
+ (Left err, _nextGlossState) -> Left err
+ (Right glossedBlock, nextGlossState) -> Right (glossedBlock, nextGlossState)
+
+meaning :: [Raw.Block] -> Either GlossError [Sem.Block]
+meaning blocks = evalState (runExceptT (glossBlocks blocks)) initialGlossState
+
+glossExpr :: Raw.Expr -> Gloss (Sem.ExprOf VarSymbol)
+glossExpr = \case
+ Raw.ExprVar v ->
+ pure $ Sem.TermVar v
+ Raw.ExprInteger loc n ->
+ pure $ Sem.TermSymbol loc (Sem.SymbolInteger n) []
+ Raw.ExprOp loc f es ->
+ Sem.TermSymbol loc <$> pure (Sem.SymbolMixfix f) <*> (glossExpr `each` es)
+ Raw.ExprStructOp _loc tok maybeLabel -> do
+ maybeLabel' <- traverse glossExpr maybeLabel
+ pure $ Sem.TermSymbolStruct tok maybeLabel'
+ Raw.ExprSep _loc x t phi -> do
+ t' <- glossExpr t
+ phi' <- glossStmt phi
+ pure (Sem.TermSep x t' (abstract1 x phi'))
+ Raw.ExprReplacePred _loc y x xBound stmt -> do
+ xBound' <- glossExpr xBound
+ stmt' <- glossStmt stmt
+ let toReplacementVar z = if
+ | z == x -> Just Sem.ReplacementDomVar
+ | z == y -> Just Sem.ReplacementRangeVar
+ | otherwise -> Nothing
+ let scope = abstract toReplacementVar stmt'
+ pure (Sem.ReplacePred y x xBound' scope)
+ Raw.ExprReplace _loc e bounds phi -> do
+ e' <- glossExpr e
+ bounds' <- glossReplaceBounds bounds
+ let xs = fst <$> bounds'
+ phi'' <- case phi of
+ Just phi' -> glossStmt phi'
+ Nothing -> pure Sem.Top
+ let abstractBoundVars = abstract (\x -> List.find (== x) (toList xs))
+ pure $ Sem.ReplaceFun bounds' (abstractBoundVars e') (abstractBoundVars phi'')
+ where
+ glossReplaceBounds
+ :: NonEmpty (VarSymbol, Raw.Expr)
+ -> Gloss (NonEmpty (VarSymbol, Sem.Term))
+ glossReplaceBounds
+ ((firstBinder, firstDomain) :| remainingBounds) = do
+ firstDomain' <- glossExpr firstDomain
+ remainingBounds' <-
+ go (Set.singleton firstBinder) remainingBounds
+ pure ((firstBinder, firstDomain') :| remainingBounds')
+ where
+ go
+ :: Set VarSymbol
+ -> [(VarSymbol, Raw.Expr)]
+ -> Gloss [(VarSymbol, Sem.Term)]
+ go _precedingBinders [] = pure []
+ go precedingBinders ((binder, domain) : laterBounds) = do
+ domain' <- glossExpr domain
+ -- Folding a glossed domain visits only free occurrences.
+ case List.find
+ (`Set.member` precedingBinders)
+ (toList domain') of
+ Just occurrence ->
+ throwError
+ (DependentReplacementDomainNotSupported
+ (locate occurrence))
+ Nothing -> do
+ laterBounds' <-
+ go
+ (Set.insert binder precedingBinders)
+ laterBounds
+ pure ((binder, domain') : laterBounds')
+ Raw.ExprFiniteSet loc es -> do
+ es' <- glossExpr `each` es
+ pure (Sem.finiteSet loc es')
+
+
+glossFormula :: Raw.Formula -> Gloss (Sem.ExprOf VarSymbol)
+glossFormula = \case
+ Raw.FormulaChain ch ->
+ glossChain ch
+ Raw.Connected _loc conn phi psi ->
+ glossConnective conn <*> glossFormula phi <*> glossFormula psi
+ Raw.FormulaNeg loc f ->
+ Sem.Not loc <$> glossFormula f
+ Raw.FormulaPredicate loc predi _marker es ->
+ Sem.Atomic loc <$> glossPrefixPredicate predi <*> glossExpr `each` toList es
+ Raw.PropositionalConstant _loc c ->
+ pure $ Sem.PropositionalConstant c
+ Raw.FormulaQuantified _loc quantifier xs bound phi -> do
+ bound' <- glossBound bound
+ phi' <- glossFormula phi
+ quantify <- glossQuantifier quantifier
+ pure (quantify xs (bound' (toList xs)) phi')
+
+glossChain :: Sem.Chain -> Gloss (Sem.ExprOf VarSymbol)
+glossChain ch = Sem.makeConjunction <$> makeRels (conjuncts (splat ch))
+ where
+ -- | Separate each link of the chain into separate triples.
+ splat :: Raw.Chain -> [(NonEmpty Raw.Expr, Sign, Raw.Relation, NonEmpty Raw.Expr)]
+ splat = \case
+ Raw.ChainBase es sign rel es'
+ -> [(es, sign, rel, es')]
+ Raw.ChainCons es sign rel ch'@(Raw.ChainBase es' _ _ _)
+ -> (es, sign, rel, es') : splat ch'
+ Raw.ChainCons es sign rel ch'@(Raw.ChainCons es' _ _ _)
+ -> (es, sign, rel, es') : splat ch'
+
+ -- | Take each triple and combine the lhs/rhs to make all the conjuncts.
+ conjuncts :: [(NonEmpty Raw.Expr, Sign, Raw.Relation, NonEmpty Raw.Expr)] -> [(Sign, Raw.Relation, Raw.Expr, Raw.Expr)]
+ conjuncts triples = do
+ (e1s, sign, rel, e2s) <- triples
+ e1 <- toList e1s
+ e2 <- toList e2s
+ pure (sign, rel, e1, e2)
+
+ makeRels :: [(Sign, Raw.Relation, Raw.Expr, Raw.Expr)] -> Gloss [Sem.Formula]
+ makeRels triples = for triples makeRel
+
+ makeRel :: (Sign, Raw.Relation, Raw.Expr, Raw.Expr) -> Gloss Sem.Formula
+ makeRel (sign, rel, e1, e2) = do
+ e1' <- glossExpr e1
+ e2' <- glossExpr e2
+ case rel of
+ Raw.Relation loc rel' params -> do
+ params' <- glossExpr `each` params
+ buildRelation <-
+ liftRelationApplication
+ (Sem.makeRelationApplication loc rel' params')
+ pure $ sign' loc $ buildRelation e1' e2'
+ Raw.RelationExpr loc e -> do
+ e' <- glossExpr e
+ pure (sign' loc (Sem.IsElementOf loc (Sem.TermPair loc e1' e2') e'))
+ where
+ sign' = case sign of
+ Positive -> \_ -> id
+ Negative -> Sem.Not
+
+
+glossPrefixPredicate :: Raw.PrefixPredicate -> Gloss Sem.Predicate
+glossPrefixPredicate (Raw.PrefixPredicate symb _ar) = pure (Sem.PredicateSymbol symb)
+
+
+glossNPNonEmpty :: Raw.NounPhrase NonEmpty -> Gloss (NonEmpty VarSymbol, Sem.Formula)
+glossNPNonEmpty (Raw.NounPhrase leftAdjs noun vars rightAdjs maySuchThat) = do
+ -- We interpret the noun as a predicate.
+ noun' <- glossNoun noun
+ -- Now we turn the noun and all its modifiers into statements.
+ let typings = (\v' -> noun' (Sem.TermVar v')) <$> vars
+ leftAdjs' <- forEach (toList vars) <$> glossAdjL `each` leftAdjs
+ rightAdjs' <- forEach (toList vars) <$> glossAdjR `each` rightAdjs
+ suchThat <- maybeToList <$> glossStmt `each` maySuchThat
+ let constraints = toList typings <> leftAdjs' <> rightAdjs' <> suchThat
+ pure (vars, Sem.makeConjunction constraints)
+
+
+-- | If needed, we introduce a fresh variable to reduce this to the case @NounPhrase NonEmpty@.
+glossNPList :: Raw.NounPhrase [] -> Gloss (NonEmpty VarSymbol, Sem.Formula)
+glossNPList (Raw.NounPhrase leftAdjs noun vars rightAdjs maySuchThat) = do
+ vars' <- case vars of
+ [] -> (:| []) <$> freshVar
+ v:vs -> pure (v :| vs)
+ glossNPNonEmpty $ Raw.NounPhrase leftAdjs noun vars' rightAdjs maySuchThat
+
+-- Returns a predicate for a term (the constraints) and the optional such-that clause.
+-- We treat suchThat separately since multiple terms can share the same such-that clause.
+glossNPMaybe :: Raw.NounPhrase Maybe -> Gloss (Sem.Term -> Sem.Formula, Maybe Sem.Formula)
+glossNPMaybe (Raw.NounPhrase leftAdjs noun mayVar rightAdjs maySuchThat) = do
+ case mayVar of
+ Nothing -> do
+ glossNP leftAdjs noun rightAdjs maySuchThat
+ Just v' -> do
+ -- Next we desugar all the modifiers into statements.
+ leftAdjs' <- apply v' <$> glossAdjL `each` leftAdjs
+ rightAdjs' <- apply v' <$> glossAdjR `each` rightAdjs
+ maySuchThat' <- glossStmt `each` maySuchThat
+ let constraints = leftAdjs' <> rightAdjs'
+ -- Finally we translate the noun itself.
+ noun' <- glossNoun noun
+ pure case constraints of
+ [] -> (\t -> noun' t, maySuchThat')
+ _ -> (\t -> noun' t `Sem.And` Sem.makeConjunction (eq t v' : constraints), maySuchThat')
+ where
+ eq t v = Sem.Equals Nowhere t (Sem.TermVar v)
+ apply :: VarSymbol -> [Sem.Term -> Sem.Formula] -> [Sem.Formula]
+ apply v stmts = [stmt (Sem.TermVar v) | stmt <- stmts]
+
+-- | Gloss a noun without a variable name.
+-- Returns a predicate for a term (the constraints) and the optional such-that clause.
+-- We treat suchThat separately since multiple terms can share the same such-that clause.
+glossNP :: [Raw.AdjL] -> Raw.Noun -> [Raw.AdjR] -> Maybe Raw.Stmt -> Gloss (Sem.Term -> Sem.ExprOf VarSymbol, Maybe Sem.Formula)
+glossNP leftAdjs noun rightAdjs maySuchThat = do
+ noun' <- glossNoun noun
+ leftAdjs' <- glossAdjL `each` leftAdjs
+ rightAdjs' <- glossAdjR `each` rightAdjs
+ maySuchThat' <- glossStmt `each` maySuchThat
+ let constraints = [noun'] <> leftAdjs' <> rightAdjs'
+ pure (\t -> Sem.makeConjunction (flap constraints t), maySuchThat')
+
+
+-- | If we have a plural noun with multiple variables, then we need to desugar
+-- adjectives to apply to each individual variable.
+forEach :: Applicative t => t VarSymbol -> t (Sem.Term -> a) -> t a
+forEach vs'' stmts = do
+ v <- vs''
+ stmt <- stmts
+ pure $ stmt (Sem.TermVar v)
+
+
+glossAdjL :: Raw.AdjL -> Gloss (Sem.Term -> Sem.Formula)
+glossAdjL (Raw.AdjL loc pat es) = do
+ (es', quantifies) <- unzip <$> glossTerm `each` es
+ let quantify = compose $ reverse quantifies
+ pure $ \t -> quantify $ Sem.FormulaAdj loc t pat es'
+
+
+-- | Since we need to be able to remove negation in verb phrases,
+-- we need to have 'Sem.Stmt' as the target. We do not yet have
+-- the term representing the subject, hence the parameter 'Sem.Expr'.
+glossAdjR :: Raw.AdjR -> Gloss (Sem.Term -> Sem.Formula)
+glossAdjR = \case
+ Raw.AdjR _loc pat [e] | pat == Raw.mkLexicalItem (unsafeReadPhrase "equal to ?") "eq" -> do
+ (e', quantify) <- glossTerm e
+ pure $ \t -> quantify $ Sem.Equals Nowhere t e'
+ Raw.AdjR _loc pat es -> do
+ (es', quantifies) <- unzip <$> glossTerm `each` es
+ let quantify = compose $ reverse quantifies
+ pure $ \t -> quantify $ Sem.FormulaAdj Nowhere t pat es'
+ Raw.AttrRThat vp -> glossVP vp
+
+
+glossAdj :: Raw.AdjOf Raw.Term -> Gloss (Sem.ExprOf VarSymbol -> Sem.Formula)
+glossAdj adj = case adj of
+ Raw.Adj loc pat [e] | pat == Raw.mkLexicalItem (unsafeReadPhrase "equal to ?") "eq" -> do
+ (e', quantify) <- glossTerm e
+ pure $ \t -> quantify $ Sem.Equals loc t e'
+ Raw.Adj loc pat es -> do
+ (es', quantifies) <- unzip <$> glossTerm `each` es
+ let quantify = compose $ reverse quantifies
+ pure $ \t -> quantify $ Sem.FormulaAdj loc t pat es'
+
+glossVP :: Raw.VerbPhrase -> Gloss (Sem.Term -> Sem.Formula)
+glossVP = \case
+ Raw.VPVerb verb -> glossVerb verb
+ Raw.VPAdj adjs -> do
+ mkAdjs <- glossAdj `each` toList adjs
+ pure (\x -> Sem.makeConjunction [mkAdj x | mkAdj <- mkAdjs])
+ Raw.VPVerbNot verb -> (Sem.Not Nowhere .) <$> glossVerb verb
+ Raw.VPAdjNot adjs -> (Sem.Not Nowhere .) <$> glossVP (Raw.VPAdj adjs)
+
+
+glossVerb :: Raw.Verb -> Gloss (Sem.Term -> Sem.Formula)
+glossVerb (Raw.Verb loc pat es) = do
+ (es', quantifies) <- unzip <$> glossTerm `each` es
+ let quantify = compose $ reverse quantifies
+ pure $ \ t -> quantify $ Sem.FormulaVerb loc t pat es'
+
+
+glossNoun :: Raw.Noun -> Gloss (Sem.Term -> Sem.Formula)
+glossNoun (Raw.Noun loc pat es) = do
+ (es', quantifies) <- unzip <$> glossTerm `each` es
+ let quantify = compose $ reverse quantifies
+ pure case Raw.sg (Raw.lexicalItemSgPlPhrase pat) of
+ -- Everything is a set
+ [Just (Sem.Word "set")] -> const Sem.Top
+ _ -> \e' -> quantify (Sem.FormulaNoun loc e' pat es')
+
+
+glossFun :: Raw.Fun -> Gloss (Sem.Term, Sem.Formula -> Sem.Formula)
+glossFun (Raw.Fun loc phrase es) = do
+ (es', quantifies) <- unzip <$> glossTerm `each` es
+ let quantify = compose $ reverse quantifies
+ pure (Sem.TermSymbol loc (Sem.SymbolFun phrase) es', quantify)
+
+
+glossTerm :: Raw.Term -> Gloss (Sem.Term, Sem.Formula -> Sem.Formula)
+glossTerm = \case
+ Raw.TermExpr e ->
+ (, id) <$> glossExpr e
+ Raw.TermFun f ->
+ glossFun f
+ Raw.TermIota location _variable _statement ->
+ rejectIotaTerm location
+ Raw.TermQuantified _quantifier loc _nounPhrase ->
+ throwError (QuantifiedTermRequiresResolvedContext loc)
+
+rejectIotaTerm :: Location -> Gloss a
+rejectIotaTerm =
+ throwError . IotaTermNotSupported
+
+
+data H0QuantifiedTerm = H0QuantifiedTerm
+ { h0Quantifier :: Raw.Quantifier
+ , h0QuantifiedBinder :: H0ResolvedBinder
+ , h0QuantifiedConstraints :: [H0Expr]
+ }
+
+data H0TermPlan = H0TermPlan
+ { h0TermExpression :: H0Expr
+ , h0TermEnvironment :: H0LexicalEnvironment
+ , h0TermQuantifiers :: [H0QuantifiedTerm]
+ }
+
+data H0TermsPlan = H0TermsPlan
+ { h0TermExpressions :: [H0Expr]
+ , h0TermsEnvironment :: H0LexicalEnvironment
+ , h0TermsQuantifiers :: [H0QuantifiedTerm]
+ }
+
+glossH0Terms
+ :: H0LexicalEnvironment
+ -> [Raw.Term]
+ -> Gloss H0TermsPlan
+glossH0Terms initialEnvironment =
+ go initialEnvironment mempty [] []
+ where
+ go environment _seenBinders expressions quantifiers [] =
+ pure
+ H0TermsPlan
+ { h0TermExpressions = reverse expressions
+ , h0TermsEnvironment = environment
+ , h0TermsQuantifiers = reverse quantifiers
+ }
+ go environment seenBinders expressions quantifiers (term : terms) = do
+ termPlan <- glossH0Term environment term
+ nextSeenBinders <-
+ foldM
+ addSiblingBinder
+ seenBinders
+ (h0TermQuantifiers termPlan)
+ go
+ (h0TermEnvironment termPlan)
+ nextSeenBinders
+ (h0TermExpression termPlan : expressions)
+ (reverse (h0TermQuantifiers termPlan) <> quantifiers)
+ terms
+
+ addSiblingBinder seenBinders quantifiedTerm =
+ case binderDisplayHint binderTrivia of
+ Nothing ->
+ pure seenBinders
+ Just displayName ->
+ case Map.lookup displayName seenBinders of
+ Nothing ->
+ pure
+ (Map.insert
+ displayName
+ binderTrivia
+ seenBinders)
+ Just firstBinderTrivia ->
+ throwError
+ (DuplicateQuantifiedNounBinder
+ (binderDeclarationLocation
+ firstBinderTrivia)
+ (binderDeclarationLocation
+ binderTrivia)
+ displayName)
+ where
+ binderTrivia =
+ h0BinderTrivia
+ (h0QuantifiedBinder quantifiedTerm)
+
+glossH0Term
+ :: H0LexicalEnvironment
+ -> Raw.Term
+ -> Gloss H0TermPlan
+glossH0Term environment = \case
+ Raw.TermExpr expression -> do
+ expression' <- resolveH0Expr environment <$> glossExpr expression
+ pure
+ H0TermPlan
+ { h0TermExpression = expression'
+ , h0TermEnvironment = environment
+ , h0TermQuantifiers = []
+ }
+ Raw.TermFun (Raw.Fun location symbol arguments) -> do
+ argumentsPlan <- glossH0Terms environment arguments
+ pure
+ H0TermPlan
+ { h0TermExpression =
+ Sem.TermSymbol
+ location
+ (Sem.SymbolFun symbol)
+ (h0TermExpressions argumentsPlan)
+ , h0TermEnvironment =
+ h0TermsEnvironment argumentsPlan
+ , h0TermQuantifiers =
+ h0TermsQuantifiers argumentsPlan
+ }
+ Raw.TermIota location _variable _statement ->
+ rejectIotaTerm location
+ Raw.TermQuantified quantifier location nounPhrase -> do
+ let writtenName = case nounPhrase of
+ Raw.NounPhrase _ _ name _ _ -> name
+ binder <- freshH0Binder location writtenName
+ let nextEnvironment = pushH0Binder binder environment
+ witness = Sem.TermVar (LocalRef (h0BinderId binder))
+ constraints <-
+ glossH0QuantifiedNoun
+ nextEnvironment
+ witness
+ nounPhrase
+ pure
+ H0TermPlan
+ { h0TermExpression = witness
+ , h0TermEnvironment = nextEnvironment
+ , h0TermQuantifiers =
+ [ H0QuantifiedTerm
+ { h0Quantifier = quantifier
+ , h0QuantifiedBinder = binder
+ , h0QuantifiedConstraints = constraints
+ }
+ ]
+ }
+
+applyH0Quantifiers
+ :: [H0QuantifiedTerm]
+ -> H0Expr
+ -> Gloss H0Expr
+applyH0Quantifiers quantifiers body =
+ foldrM applyQuantifier body quantifiers
+ where
+ applyQuantifier quantifiedTerm continuation = do
+ let constrainedBody =
+ applyQuantifierConstraints
+ (h0Quantifier quantifiedTerm)
+ (h0QuantifiedConstraints quantifiedTerm)
+ continuation
+ scope <-
+ abstractH0Binder
+ (h0QuantifiedBinder quantifiedTerm)
+ constrainedBody
+ pure case h0Quantifier quantifiedTerm of
+ Raw.Universally ->
+ Sem.Quantified Sem.Universally scope
+ Raw.Existentially ->
+ Sem.Quantified Sem.Existentially scope
+ Raw.Nonexistentially ->
+ Sem.Not
+ Nowhere
+ (Sem.Quantified Sem.Existentially scope)
+
+glossH0QuantifiedNoun
+ :: H0LexicalEnvironment
+ -> H0Expr
+ -> Raw.NounPhrase Maybe
+ -> Gloss [H0Expr]
+glossH0QuantifiedNoun
+ environment
+ witness
+ (Raw.NounPhrase leftAdjectives noun _name rightAdjectives maySuchThat) = do
+ nounConstraint <- glossH0Noun environment witness noun
+ leftConstraints <-
+ for leftAdjectives (glossH0AdjL environment witness)
+ rightConstraints <-
+ for rightAdjectives (glossH0AdjR environment witness)
+ suchThatConstraint <-
+ traverse (glossH0Stmt environment) maySuchThat
+ pure
+ ( maybeToList suchThatConstraint
+ <> [ Sem.makeConjunction
+ ( nounConstraint
+ : leftConstraints
+ <> rightConstraints
+ )
+ ]
+ )
+
+glossH0NPMaybe
+ :: H0LexicalEnvironment
+ -> H0Expr
+ -> Raw.NounPhrase Maybe
+ -> Gloss (H0Expr, Maybe H0Expr)
+glossH0NPMaybe
+ environment
+ subject
+ (Raw.NounPhrase leftAdjectives noun mayName rightAdjectives maySuchThat) = do
+ nounConstraint <- glossH0Noun environment subject noun
+ suchThatConstraint <-
+ traverse (glossH0Stmt environment) maySuchThat
+ case mayName of
+ Nothing -> do
+ leftConstraints <-
+ for leftAdjectives (glossH0AdjL environment subject)
+ rightConstraints <-
+ for rightAdjectives (glossH0AdjR environment subject)
+ pure
+ ( Sem.makeConjunction
+ ( nounConstraint
+ : leftConstraints
+ <> rightConstraints
+ )
+ , suchThatConstraint
+ )
+ Just name -> do
+ let namedSubject =
+ Sem.TermVar
+ (resolveH0Reference environment name)
+ leftConstraints <-
+ for leftAdjectives
+ (glossH0AdjL environment namedSubject)
+ rightConstraints <-
+ for rightAdjectives
+ (glossH0AdjR environment namedSubject)
+ let modifierConstraints =
+ leftConstraints <> rightConstraints
+ constraint = case modifierConstraints of
+ [] ->
+ nounConstraint
+ _ ->
+ nounConstraint
+ `Sem.And`
+ Sem.makeConjunction
+ ( Sem.Equals
+ Nowhere
+ subject
+ namedSubject
+ : modifierConstraints
+ )
+ pure (constraint, suchThatConstraint)
+
+glossH0AdjL
+ :: H0LexicalEnvironment
+ -> H0Expr
+ -> Raw.AdjL
+ -> Gloss H0Expr
+glossH0AdjL environment subject (Raw.AdjL location lexicalPattern arguments) = do
+ argumentsPlan <- glossH0Terms environment arguments
+ applyH0Quantifiers
+ (h0TermsQuantifiers argumentsPlan)
+ (Sem.FormulaAdj
+ location
+ subject
+ lexicalPattern
+ (h0TermExpressions argumentsPlan))
+
+glossH0AdjR
+ :: H0LexicalEnvironment
+ -> H0Expr
+ -> Raw.AdjR
+ -> Gloss H0Expr
+glossH0AdjR environment subject = \case
+ Raw.AdjR _location lexicalPattern [argument]
+ | lexicalPattern
+ == Raw.mkLexicalItem
+ (unsafeReadPhrase "equal to ?")
+ "eq" -> do
+ argumentPlan <-
+ glossH0Term environment argument
+ applyH0Quantifiers
+ (h0TermQuantifiers argumentPlan)
+ (Sem.Equals
+ Nowhere
+ subject
+ (h0TermExpression argumentPlan))
+ Raw.AdjR _location lexicalPattern arguments -> do
+ argumentsPlan <- glossH0Terms environment arguments
+ applyH0Quantifiers
+ (h0TermsQuantifiers argumentsPlan)
+ (Sem.FormulaAdj
+ Nowhere
+ subject
+ lexicalPattern
+ (h0TermExpressions argumentsPlan))
+ Raw.AttrRThat verbPhrase ->
+ glossH0VP environment subject verbPhrase
+
+glossH0Adj
+ :: H0LexicalEnvironment
+ -> H0Expr
+ -> Raw.Adj
+ -> Gloss H0Expr
+glossH0Adj environment subject = \case
+ Raw.Adj location lexicalPattern [argument]
+ | lexicalPattern
+ == Raw.mkLexicalItem
+ (unsafeReadPhrase "equal to ?")
+ "eq" -> do
+ argumentPlan <-
+ glossH0Term environment argument
+ applyH0Quantifiers
+ (h0TermQuantifiers argumentPlan)
+ (Sem.Equals
+ location
+ subject
+ (h0TermExpression argumentPlan))
+ Raw.Adj location lexicalPattern arguments -> do
+ argumentsPlan <- glossH0Terms environment arguments
+ applyH0Quantifiers
+ (h0TermsQuantifiers argumentsPlan)
+ (Sem.FormulaAdj
+ location
+ subject
+ lexicalPattern
+ (h0TermExpressions argumentsPlan))
+
+glossH0VP
+ :: H0LexicalEnvironment
+ -> H0Expr
+ -> Raw.VerbPhrase
+ -> Gloss H0Expr
+glossH0VP environment subject = \case
+ Raw.VPVerb verb ->
+ glossH0Verb environment subject verb
+ Raw.VPAdj adjectives ->
+ Sem.makeConjunction
+ <$> for
+ (toList adjectives)
+ (glossH0Adj environment subject)
+ Raw.VPVerbNot verb ->
+ Sem.Not Nowhere
+ <$> glossH0Verb environment subject verb
+ Raw.VPAdjNot adjectives ->
+ Sem.Not Nowhere
+ <$> glossH0VP
+ environment
+ subject
+ (Raw.VPAdj adjectives)
+
+glossH0Verb
+ :: H0LexicalEnvironment
+ -> H0Expr
+ -> Raw.Verb
+ -> Gloss H0Expr
+glossH0Verb environment subject (Raw.Verb location lexicalPattern arguments) = do
+ argumentsPlan <- glossH0Terms environment arguments
+ applyH0Quantifiers
+ (h0TermsQuantifiers argumentsPlan)
+ (Sem.FormulaVerb
+ location
+ subject
+ lexicalPattern
+ (h0TermExpressions argumentsPlan))
+
+glossH0Noun
+ :: H0LexicalEnvironment
+ -> H0Expr
+ -> Raw.Noun
+ -> Gloss H0Expr
+glossH0Noun environment subject (Raw.Noun location lexicalPattern arguments) = do
+ argumentsPlan <- glossH0Terms environment arguments
+ let constraint = case Raw.sg (Raw.lexicalItemSgPlPhrase lexicalPattern) of
+ [Just (Sem.Word "set")] ->
+ Sem.Top
+ _ ->
+ Sem.FormulaNoun
+ location
+ subject
+ lexicalPattern
+ (h0TermExpressions argumentsPlan)
+ applyH0Quantifiers
+ (h0TermsQuantifiers argumentsPlan)
+ constraint
+
+
+
+glossStmt :: Raw.Stmt -> Gloss Sem.Formula
+glossStmt statement = do
+ resolvedStatement <- glossH0Stmt [] statement
+ lowerH0Expr resolvedStatement
+
+glossH0Stmt
+ :: H0LexicalEnvironment
+ -> Raw.Stmt
+ -> Gloss H0Expr
+glossH0Stmt environment = \case
+ Raw.StmtFormula formula ->
+ resolveH0Expr environment <$> glossFormula formula
+ Raw.StmtNeg location statement ->
+ Sem.Not location <$> glossH0Stmt environment statement
+ Raw.StmtVerbPhrase ts vp -> do
+ termsPlan <- glossH0Terms environment (toList ts)
+ statements <-
+ for
+ (h0TermExpressions termsPlan)
+ (\term ->
+ glossH0VP
+ (h0TermsEnvironment termsPlan)
+ term
+ vp)
+ applyH0Quantifiers
+ (h0TermsQuantifiers termsPlan)
+ (Sem.makeConjunction statements)
+ Raw.StmtNoun ts np -> do
+ termsPlan <- glossH0Terms environment (toList ts)
+ statements <-
+ for (h0TermExpressions termsPlan) \term -> do
+ (nounConstraint, maySuchThat) <-
+ glossH0NPMaybe
+ (h0TermsEnvironment termsPlan)
+ term
+ np
+ pure case maySuchThat of
+ Just suchThat ->
+ nounConstraint `Sem.And` suchThat
+ Nothing ->
+ nounConstraint
+ applyH0Quantifiers
+ (h0TermsQuantifiers termsPlan)
+ (Sem.makeConjunction statements)
+ Raw.StmtStruct t sp -> do
+ termPlan <- glossH0Term environment t
+ applyH0Quantifiers
+ (h0TermQuantifiers termPlan)
+ (Sem.TermSymbol
+ (locate t)
+ (Sem.SymbolPredicate
+ (Sem.PredicateNounStruct sp))
+ [h0TermExpression termPlan])
+ Raw.StmtConnected connective _location left right ->
+ Sem.Connected connective
+ <$> glossH0Stmt environment left
+ <*> glossH0Stmt environment right
+ Raw.StmtQuantPhrase _location (Raw.QuantPhrase quantifier np) statement -> do
+ (vars, constraints) <- glossNPList np
+ let nestedEnvironment =
+ hideH0Binders vars environment
+ constraints' =
+ resolveH0Expr nestedEnvironment constraints
+ statement' <-
+ glossH0Stmt nestedEnvironment statement
+ pure
+ (quantifyH0Ambient
+ quantifier
+ vars
+ [constraints']
+ statement')
+ Raw.StmtExists _location np -> do
+ (vars, constraints) <- glossNPList np
+ let nestedEnvironment =
+ hideH0Binders vars environment
+ pure
+ (quantifyH0Ambient
+ Raw.Existentially
+ vars
+ []
+ (resolveH0Expr nestedEnvironment constraints))
+ Raw.SymbolicQuantified _loc quant vs bound suchThat have -> do
+ let nestedEnvironment =
+ hideH0Binders vs environment
+ bound' <- glossBound bound
+ let boundConstraints =
+ resolveH0Expr nestedEnvironment
+ <$> bound' (toList vs)
+ suchThatConstraints <-
+ maybeToList
+ <$> traverse
+ (glossH0Stmt nestedEnvironment)
+ suchThat
+ have' <- glossH0Stmt nestedEnvironment have
+ pure
+ (quantifyH0Ambient
+ quant
+ vs
+ (boundConstraints <> suchThatConstraints)
+ have')
+
+-- Other binder forms stay on the legacy path and only mask outer H0 names.
+hideH0Binders
+ :: Foldable f
+ => f VarSymbol
+ -> H0LexicalEnvironment
+ -> H0LexicalEnvironment
+hideH0Binders variables =
+ List.filter \binder ->
+ maybe
+ True
+ (`Set.notMember` displayedNames)
+ (binderDisplayHint (h0BinderTrivia binder))
+ where
+ displayedNames =
+ Set.fromList
+ [ name
+ | NamedVarAt _ name <- toList variables
+ ]
+
+quantifyH0Ambient
+ :: Foldable f
+ => Raw.Quantifier
+ -> f VarSymbol
+ -> [H0Expr]
+ -> H0Expr
+ -> H0Expr
+quantifyH0Ambient quantifier variables constraints body =
+ case quantifier of
+ Raw.Universally ->
+ Sem.Quantified Sem.Universally scope
+ Raw.Existentially ->
+ Sem.Quantified Sem.Existentially scope
+ Raw.Nonexistentially ->
+ Sem.Not
+ Nowhere
+ (Sem.Quantified Sem.Existentially scope)
+ where
+ constrainedBody =
+ applyQuantifierConstraints quantifier constraints body
+ scope =
+ abstract
+ (\case
+ AmbientRef variable
+ | variable `elem` variables ->
+ Just variable
+ _ ->
+ Nothing)
+ constrainedBody
+
+-- | A bound applies to all listed variables. Note the use of '<**>'.
+--
+-- >>> ([1, 2, 3] <**> [(+ 10)]) == [11, 12, 13]
+--
+glossBound :: Raw.Bound -> Gloss ([VarSymbol] -> [Sem.Formula])
+glossBound = \case
+ Raw.Unbounded -> pure (const [])
+ Raw.Bounded loc sign rel term -> do
+ term' <- glossExpr term
+ let sign' = case sign of
+ Positive -> id
+ Negative -> Sem.Not loc
+ bound <- case rel of
+ Raw.Relation loc' rel' params -> do
+ params' <- glossExpr `each` params
+ buildRelation <-
+ liftRelationApplication
+ (Sem.makeRelationApplication loc' rel' params')
+ pure $ \v -> sign' $
+ buildRelation (Sem.TermVar v) term'
+ Raw.RelationExpr loc' e -> do
+ e' <- glossExpr e
+ pure $ \v -> sign' $
+ Sem.IsElementOf loc' (Sem.TermPair loc' (Sem.TermVar v) term') e'
+ pure \vs -> vs <**> [bound]
+
+
+glossConnective :: Raw.Connective -> Gloss (Sem.Formula -> Sem.Formula -> Sem.Formula)
+glossConnective conn = pure (Sem.Connected conn)
+
+
+glossAsm :: Raw.Asm -> Gloss [Sem.Asm]
+glossAsm = \case
+ Raw.AsmSuppose s -> do
+ s' <- glossStmt s
+ pure [Sem.Asm s']
+ Raw.AsmLetNoun vs np -> do
+ (np', maySuchThat) <- glossNPMaybe np
+ let f v = Sem.Asm (np' (Sem.TermVar v) )
+ let suchThat = Sem.Asm <$> maybeToList maySuchThat
+ pure (suchThat <> fmap f (toList vs))
+ Raw.AsmLetIn vs e -> do
+ e' <- glossExpr e
+ let f v = Sem.Asm (Sem.IsElementOf Nowhere (Sem.TermVar v) e')
+ pure $ fmap f (toList vs)
+ Raw.AsmLetStruct structLabel structPhrase ->
+ pure [Sem.AsmStruct structLabel structPhrase]
+ Raw.AsmLetThe _variable fun ->
+ throwError
+ (DefiniteFunctionAssumptionNotSupported
+ (locate fun))
+ Raw.AsmLetEq x e -> do
+ e' <- glossExpr e
+ pure (Sem.Asm (Sem.Equals Nowhere (Sem.TermVar x) e') : [])
+
+
+-- | A quantifier is interpreted as a quantification function that takes a nonempty list of variables,
+-- a list of formulas expressing the constraints, and the formula to be quantified as arguments.
+-- It then returns the quantification with the correct connective for the constraints.
+glossQuantifier
+ :: (Foldable t, Applicative f)
+ => Raw.Quantifier
+ -> f (t VarSymbol
+ -> [Sem.ExprOf VarSymbol]
+ -> Sem.Formula
+ -> Sem.Formula)
+glossQuantifier quantifier = pure quantify
+ where
+ quantify vs constraints body = case quantifier of
+ Raw.Universally ->
+ Sem.makeForall
+ vs
+ (applyQuantifierConstraints
+ quantifier
+ constraints
+ body)
+ Raw.Existentially ->
+ Sem.makeExists
+ vs
+ (applyQuantifierConstraints
+ quantifier
+ constraints
+ body)
+ Raw.Nonexistentially ->
+ Sem.Not
+ Nowhere
+ (Sem.makeExists
+ vs
+ (applyQuantifierConstraints
+ quantifier
+ constraints
+ body))
+
+applyQuantifierConstraints
+ :: Raw.Quantifier
+ -> [Sem.ExprOf a]
+ -> Sem.ExprOf a
+ -> Sem.ExprOf a
+applyQuantifierConstraints _quantifier [] body =
+ body
+applyQuantifierConstraints quantifier constraints body =
+ case quantifier of
+ Raw.Universally ->
+ Sem.makeConjunction constraints `Sem.Implies` body
+ Raw.Existentially ->
+ Sem.makeConjunction constraints `Sem.And` body
+ Raw.Nonexistentially ->
+ Sem.makeConjunction constraints `Sem.And` body
+
+
+glossAsms :: [Raw.Asm] -> Gloss [Sem.Asm]
+glossAsms asms = do
+ asms' <- glossAsm `each` asms
+ pure $ concat asms'
+
+
+glossAxiom :: Raw.Axiom -> Gloss Sem.Axiom
+glossAxiom (Raw.Axiom asms f) = Sem.Axiom <$> glossAsms asms <*> glossStmt f
+
+
+glossLemma :: Raw.Claim -> Gloss Sem.Lemma
+glossLemma (Raw.Claim asms f) = Sem.Lemma <$> glossAsms asms <*> glossStmt f
+
+
+glossDefn
+ :: Location
+ -> Sem.Marker
+ -> Raw.Defn
+ -> Gloss Sem.Defn
+glossDefn blockLocation blockMarker = \case
+ Raw.Defn asms h f ->
+ glossDefnHead blockLocation h <*> glossAsms asms <*> glossStmt f
+ Raw.DefnFun asms (Raw.Fun _loc fun vs) _ e -> do
+ asms' <- glossAsms asms
+ e' <- case e of
+ Raw.TermQuantified _ loc _ ->
+ throwError
+ (GlossDefnError
+ loc
+ DefnErrorQuantifiedRhsTerm
+ blockMarker)
+ _ -> fst <$> glossTerm e
+ pure $ Sem.DefnFun asms' fun vs e'
+ Raw.DefnOp (Raw.SymbolPattern op vs) e ->
+ Sem.DefnOp op vs <$> glossExpr e
+
+
+-- | A definition head is interpreted as a builder of a definition,
+-- depending on a previous assumptions and on a rhs.
+glossDefnHead
+ :: Location
+ -> Raw.DefnHead
+ -> Gloss ([Sem.Asm] -> Sem.Formula -> Sem.Defn)
+glossDefnHead blockLocation = \case
+ -- TODO add info from NP.
+ Raw.DefnAdj _mnp v (Raw.Adj _loc adj vs) -> do
+ pure $ \asms f -> Sem.DefnPredicate asms (Sem.PredicateAdj adj) (v :| vs) f
+ --mnp' <- glossNPMaybe `each` mnp
+ --pure $ case mnp' of
+ -- Nothing -> \asms f -> Sem.DefnPredicate asms (Sem.PredicateAdj adj') (v :| vs) f
+ -- Just np' -> \asms f -> Sem.DefnPredicate asms (Sem.PredicateAdj adj') (v :| vs) (Sem.FormulaAnd (np' v) f)
+ Raw.DefnVerb _mnp v (Raw.Verb _loc verb vs) ->
+ pure $ \asms f -> Sem.DefnPredicate asms (Sem.PredicateVerb verb) (v :| vs) f
+ Raw.DefnNoun v (Raw.Noun _loc noun vs) ->
+ pure $ \asms f -> Sem.DefnPredicate asms (Sem.PredicateNoun noun) (v :| vs) f
+ Raw.DefnRel v1 rel params v2 -> do
+ liftRelationApplication
+ (Sem.checkRelationParameterArity
+ blockLocation
+ rel
+ params)
+ pure \asms f ->
+ let args = case params of
+ p : ps -> p :| (ps <> [v1, v2])
+ [] -> v1 :| [v2]
+ in Sem.DefnPredicate asms (Sem.PredicateRelation rel) args f
+ Raw.DefnSymbolicPredicate (Raw.PrefixPredicate symb _ar) _marker vs ->
+ pure $ \asms f -> Sem.DefnPredicate asms (Sem.PredicateSymbol symb) vs f
+
+
+glossProof :: Raw.Proof -> Gloss Sem.Proof
+glossProof = \case
+ Raw.Omitted loc ->
+ pure (Sem.Omitted loc)
+ Raw.Qed loc by ->
+ pure (Sem.Qed loc by)
+ Raw.Contradiction loc by ->
+ pure (Sem.Contradiction loc by)
+ Raw.ByContradiction loc proof ->
+ Sem.ByContradiction loc <$> glossProof proof
+ Raw.BySetInduction loc mt proof ->
+ Sem.BySetInduction loc <$> mmt' <*> glossProof proof
+ where
+ mmt' = case mt of
+ Nothing -> pure Nothing
+ Just (Raw.TermExpr (Raw.ExprVar x)) -> pure (Just (Sem.TermVar x))
+ Just _t -> throwError (GlossInductionError loc)
+ Raw.ByOrdInduction loc proof ->
+ Sem.ByOrdInduction loc <$> glossProof proof
+ Raw.ByCase loc cases -> Sem.ByCase loc <$> glossCase `each` cases
+ Raw.Have loc _ms s by proof -> case s of
+ -- Pragmatics: an existential @Have@ implicitly
+ -- introduces the witness and is interpreted as a @Take@ construct.
+ Raw.SymbolicExists _loc vs bound suchThat -> do
+ bound' <- glossBound bound
+ suchThat' <- glossStmt suchThat
+ proof' <- glossProof proof
+ pure (Sem.Take loc vs (Sem.makeConjunction (suchThat' : bound' (toList vs))) by proof')
+ _otherwise ->
+ Sem.Have loc <$> glossStmt s <*> pure by <*> glossProof proof
+ Raw.Assume loc stmt proof ->
+ Sem.Assume loc <$> glossStmt stmt <*> glossProof proof
+ Raw.FixSymbolic loc xs bound proof -> do
+ bound' <- glossBound bound
+ proof' <- glossProof proof
+ pure (Sem.Fix loc xs (Sem.makeConjunction (bound' (toList xs))) proof')
+ Raw.FixSuchThat loc xs stmt proof -> do
+ stmt' <- glossStmt stmt
+ proof' <- glossProof proof
+ pure (Sem.Fix loc xs stmt' proof')
+ Raw.TakeVar loc vs bound suchThat by proof -> do
+ bound' <- glossBound bound
+ suchThat' <- glossStmt suchThat
+ proof' <- glossProof proof
+ pure (Sem.Take loc vs (Sem.makeConjunction (suchThat' : bound' (toList vs))) by proof')
+ Raw.TakeNoun loc np by proof -> do
+ (vs, constraints) <- glossNPList np
+ proof' <- glossProof proof
+ pure $ Sem.Take loc vs constraints by proof'
+ Raw.Subclaim loc subclaim subproof proof ->
+ Sem.Subclaim loc <$> glossStmt subclaim <*> glossProof subproof <*> glossProof proof
+ Raw.Suffices loc reduction by proof ->
+ Sem.Suffices loc <$> glossStmt reduction <*> pure by <*> glossProof proof
+ Raw.Define loc var term proof ->
+ Sem.Define loc var <$> glossExpr term <*> glossProof proof
+ Raw.DefineFunction loc funVar argVar valueExpr domVar domExpr proof ->
+ if domVar == argVar
+ then Sem.DefineFunction loc funVar argVar <$> glossExpr valueExpr <*> glossExpr domExpr <*> glossProof proof
+ else
+ throwError
+ (GlossProofFunctionArgumentMismatch
+ loc
+ argVar
+ domVar)
+
+ Raw.DefineFunctionLocal loc funVar domVar ranExpr funVar2 argVar definitions proof -> do
+ if funVar == funVar2
+ then Sem.DefineFunctionLocal loc funVar argVar domVar <$> glossExpr ranExpr <*> (glossLocalFunctionExprDef `each` definitions) <*> glossProof proof
+ else
+ throwError
+ (GlossProofFunctionNameMismatch
+ loc
+ funVar
+ funVar2)
+ Raw.Calc loc calcQuant calc proof ->
+ Sem.Calc loc <$> glossCalcQuantifier calcQuant <*> glossCalc calc <*> glossProof proof
+
+glossCalcQuantifier :: Maybe Raw.CalcQuantifier -> Gloss Sem.CalcQuantifier
+glossCalcQuantifier Nothing = pure Sem.CalcUnquantified
+glossCalcQuantifier (Just (Raw.CalcQuantifier xs bound maySuchThat)) = do
+ bound' <- glossBound bound
+ maySuchThat' <- glossStmt `each` maySuchThat
+ let constraints = bound' (toList xs) <> maybeToList maySuchThat'
+ let calcGuard = case constraints of
+ [] -> Nothing
+ _ -> Just (Sem.makeConjunction constraints)
+ pure (Sem.CalcForall xs calcGuard)
+
+glossLocalFunctionExprDef :: (Raw.Expr, Raw.Formula) -> Gloss (Sem.Term, Sem.Formula)
+glossLocalFunctionExprDef (definingExpression, localDomain) = do
+ e <- glossExpr definingExpression
+ d <- glossFormula localDomain
+ pure (e,d)
+
+
+glossCase :: Raw.Case -> Gloss Sem.Case
+glossCase (Raw.Case caseOf proof) = Sem.Case <$> glossStmt caseOf <*> glossProof proof
+
+glossCalc :: Raw.Calc -> Gloss Sem.Calc
+glossCalc = \case
+ Raw.Equation e eqns -> do
+ e' <- glossExpr e
+ eqns' <- (\(ei, ji) -> (,ji) <$> glossExpr ei) `each` eqns
+ pure (Sem.Equation e' eqns')
+ Raw.Biconditionals p ps -> do
+ p' <- glossFormula p
+ ps' <- (\(pi, ji) -> (,ji) <$> glossFormula pi) `each` ps
+ pure (Sem.Biconditionals p' ps')
+
+glossSignature :: Raw.Signature -> Gloss Sem.Signature
+glossSignature sig = case sig of
+ Raw.SignatureAdj v (Raw.Adj _loc adj vs) ->
+ pure $ Sem.SignaturePredicate (Sem.PredicateAdj adj) (v :| vs)
+ Raw.SignatureVerb v (Raw.Verb _loc verb vs) ->
+ pure $ Sem.SignaturePredicate (Sem.PredicateVerb verb) (v :| vs)
+ Raw.SignatureNoun v (Raw.Noun _loc noun vs) ->
+ pure $ Sem.SignaturePredicate (Sem.PredicateNoun noun) (v :| vs)
+ Raw.SignatureSymbolic (Raw.SymbolPattern op vs) np -> do
+ (np', maySuchThat) <- glossNPMaybe np
+ let andSuchThat phi = case maySuchThat of
+ Just suchThat -> phi `Sem.And` suchThat
+ Nothing -> phi
+ let op' = Sem.TermOp Nowhere op (Sem.TermVar <$> vs)
+ v <- freshVar
+ let v' = Sem.TermVar v
+ pure $ Sem.SignatureFormula $ Sem.makeForall [v] ((Sem.Equals Nowhere v' op') `Sem.Implies` andSuchThat (np' v'))
+
+
+glossStructDefn :: Raw.StructDefn -> Gloss Sem.StructDefn
+glossStructDefn (Raw.StructDefn phrase base carrier fixes assumes) = do
+ assumes' <- (\(m, stmt) -> (m,) <$> glossStmt stmt) `each` assumes
+ let base' = Set.fromList base
+ let fixes' = Set.fromList fixes
+ pure $ Sem.StructDefn phrase base' carrier fixes' assumes'
+
+
+glossAbbreviation
+ :: Location
+ -> Sem.Marker
+ -> Raw.Abbreviation
+ -> Gloss Sem.Abbreviation
+glossAbbreviation blockLocation blockMarker = \case
+ Raw.AbbreviationAdj x (Raw.Adj _loc adj xs) stmt ->
+ build
+ (Sem.SymbolPredicate (Sem.PredicateAdj adj))
+ (x : xs)
+ (glossStmt stmt)
+ Raw.AbbreviationVerb x (Raw.Verb _loc verb xs) stmt ->
+ build
+ (Sem.SymbolPredicate (Sem.PredicateVerb verb))
+ (x : xs)
+ (glossStmt stmt)
+ Raw.AbbreviationNoun x (Raw.Noun _loc noun xs) stmt ->
+ build
+ (Sem.SymbolPredicate (Sem.PredicateNoun noun))
+ (x : xs)
+ (glossStmt stmt)
+ Raw.AbbreviationRel x rel params y stmt -> do
+ liftRelationApplication
+ (Sem.checkRelationParameterArity
+ blockLocation
+ rel
+ params)
+ build
+ (Sem.SymbolPredicate (Sem.PredicateRelation rel))
+ (params <> [x, y])
+ (glossStmt stmt)
+ Raw.AbbreviationFun (Raw.Fun _loc fun xs) t ->
+ build
+ (Sem.SymbolFun fun)
+ xs
+ (fst <$> glossTerm t)
+ Raw.AbbreviationEq (Raw.SymbolPattern op xs) e ->
+ build
+ (Sem.SymbolMixfix op)
+ xs
+ (glossExpr e)
+ where
+ build =
+ makeAbbreviation blockLocation blockMarker
+
+makeAbbreviation
+ :: Location
+ -> Sem.Marker
+ -> Sem.Symbol
+ -> [VarSymbol]
+ -> Gloss Sem.Expr
+ -> Gloss Sem.Abbreviation
+makeAbbreviation blockLocation blockMarker symbol rawParameters elaborateBody = do
+ parameters <-
+ either
+ (throwError
+ . GlossAbbreviationError
+ blockLocation
+ blockMarker
+ . DuplicateAbbreviationParameters)
+ pure
+ (validateAbbreviationParameters rawParameters)
+ body <- elaborateBody
+ scope <-
+ either
+ (throwError
+ . GlossAbbreviationError
+ blockLocation
+ blockMarker
+ . FreeAbbreviationBodyVariables)
+ pure
+ (abstractClosedAbbreviation parameters body)
+ pure (Sem.Abbreviation symbol scope)
+ where
+ validateAbbreviationParameters
+ :: [VarSymbol]
+ -> Either
+ (NonEmpty VarSymbol)
+ (Map VarSymbol Int)
+ validateAbbreviationParameters parameters =
+ case NonEmpty.nonEmpty (duplicateParameters parameters) of
+ Just duplicates ->
+ Left duplicates
+ Nothing ->
+ Right (Map.fromList (zip parameters [0 ..]))
+
+ abstractClosedAbbreviation
+ :: Map VarSymbol Int
+ -> Sem.Expr
+ -> Either
+ (NonEmpty VarSymbol)
+ (Scope Int Sem.ExprOf Void)
+ abstractClosedAbbreviation parameterIndices body =
+ case NonEmpty.nonEmpty unknownVariables of
+ Just variables ->
+ Left variables
+ Nothing ->
+ case traverse bindParameter body of
+ Left variable ->
+ Left (variable :| [])
+ Right scopedBody ->
+ Right (toScope scopedBody)
+ where
+ unknownVariables =
+ Set.toAscList
+ ( Sem.freeVars body
+ `Set.difference`
+ Map.keysSet parameterIndices
+ )
+
+ bindParameter
+ :: VarSymbol
+ -> Either
+ VarSymbol
+ (Var Int Void)
+ bindParameter variable =
+ case Map.lookup variable parameterIndices of
+ Nothing ->
+ Left variable
+ Just parameterIndex ->
+ Right (B parameterIndex)
+
+ duplicateParameters :: [VarSymbol] -> [VarSymbol]
+ duplicateParameters =
+ reverse . third . foldl' step (mempty, mempty, [])
+ where
+ step (seen, reported, duplicates) variable
+ | variable `Set.notMember` seen =
+ (Set.insert variable seen, reported, duplicates)
+ | variable `Set.member` reported =
+ (seen, reported, duplicates)
+ | otherwise =
+ ( seen
+ , Set.insert variable reported
+ , variable : duplicates
+ )
+
+ third (_seen, _reported, duplicates) =
+ duplicates
+
+glossInductive :: Raw.Inductive -> Gloss Sem.Inductive
+glossInductive (Raw.Inductive (Raw.SymbolPattern symbol args) domain rules) =
+ Sem.Inductive symbol args <$> glossExpr domain <*> (glossRule `each` rules)
+ where
+ glossRule (Raw.IntroRule phis psi) = Sem.IntroRule <$> (glossFormula `each` phis) <*> glossFormula psi
+
+glossDatatype :: Raw.Datatype -> Gloss Sem.Datatype
+glossDatatype rawDatatype = do
+ let datatypeHeadExpr = Raw.datatypeHeadExpr rawDatatype
+ rawClauses = Raw.datatypeClauses rawDatatype
+ datatypeHead <- glossDatatypeHead datatypeHeadExpr
+ datatypeClauses <- glossDatatypeClause datatypeHead `each` rawClauses
+ pure (Sem.Datatype datatypeHead datatypeClauses)
+ where
+ glossDatatypeHead :: Raw.Expr -> Gloss Sem.SymbolPattern
+ glossDatatypeHead expr = case expr of
+ Raw.ExprOp _loc item [] ->
+ pure (Sem.SymbolPattern item [])
+ _ ->
+ throwError (GlossDatatypeHeadError (locate expr))
+
+ glossDatatypeClause :: Sem.SymbolPattern -> Raw.DatatypeClause -> Gloss Sem.DatatypeClause
+ glossDatatypeClause datatypeHead rawClause = do
+ let constructorExpr = Raw.datatypeClauseConstructorExpr rawClause
+ targetExpr = Raw.datatypeClauseTargetExpr rawClause
+ rawPremises = Raw.datatypeClausePremises rawClause
+ datatypeTarget <- glossDatatypeHead targetExpr
+ unless (datatypeTarget == datatypeHead) do
+ throwError (GlossDatatypeClauseTargetError (locate targetExpr))
+ datatypeClauseConstructor <- glossDatatypeConstructor constructorExpr
+ datatypeClausePremises <- traverse glossDatatypePremise rawPremises
+ pure (Sem.DatatypeClause datatypeClauseConstructor datatypeClausePremises)
+
+ glossDatatypeConstructor :: Raw.Expr -> Gloss Sem.SymbolPattern
+ glossDatatypeConstructor expr = case expr of
+ Raw.ExprOp _loc item args -> do
+ vars <- traverse glossConstructorArg args
+ pure (Sem.SymbolPattern item vars)
+ _ ->
+ throwError (GlossDatatypeConstructorError (locate expr))
+
+ glossConstructorArg :: Raw.Expr -> Gloss VarSymbol
+ glossConstructorArg = \case
+ Raw.ExprVar x -> pure x
+ expr -> throwError (GlossDatatypeConstructorError (locate expr))
+
+ glossDatatypePremise :: (VarSymbol, Raw.Expr) -> Gloss (VarSymbol, Sem.Expr)
+ glossDatatypePremise (x, domain) =
+ (x,) <$> glossExpr domain
+
+glossBlock :: Raw.Block -> Gloss Sem.Block
+glossBlock = \case
+ Raw.BlockAxiom loc _title marker axiom ->
+ Sem.BlockAxiom loc marker <$> glossAxiom axiom
+ Raw.BlockClaim _claimKind loc _title marker lemma ->
+ Sem.BlockLemma loc marker <$> glossLemma lemma
+ Raw.BlockProof startLoc proof endLoc ->
+ Sem.BlockProof startLoc endLoc <$> glossProof proof
+ Raw.BlockDefn loc _title marker defn -> do
+ defn' <- glossDefn loc marker defn
+ whenLeft (isWellformedDefn defn') (\err -> throwError (GlossDefnError loc err marker))
+ pure $ Sem.BlockDefn loc marker defn'
+ Raw.BlockAbbr loc _title marker abbr ->
+ Sem.BlockAbbr loc marker
+ <$> glossAbbreviation loc marker abbr
+ Raw.BlockSig loc _title marker asms sig ->
+ Sem.BlockSig loc marker <$> glossAsms asms <*> glossSignature sig
+ Raw.BlockStruct loc _title m structDefn ->
+ Sem.BlockStruct loc m <$> glossStructDefn structDefn
+ Raw.BlockData loc _title marker datatype ->
+ Sem.BlockData loc marker <$> glossDatatype datatype
+ Raw.BlockInductive loc _title marker ind ->
+ Sem.BlockInductive loc marker <$> glossInductive ind
+
+
+glossBlocks :: [Raw.Block] -> Gloss [Sem.Block]
+glossBlocks blocks = glossBlock `each` blocks