123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796 |
- ..
- ::
- module language.reflection where
- open import Agda.Builtin.Sigma
- open import Agda.Builtin.Unit
- open import Agda.Builtin.Nat
- open import Agda.Builtin.List
- open import Agda.Builtin.Float
- open import Agda.Builtin.Bool
- open import Agda.Builtin.Char
- open import Agda.Builtin.String
- open import Agda.Builtin.Word
- open import Agda.Builtin.Equality
- open import Agda.Primitive
- data ⊥ : Set where
- pattern [_] x = x ∷ []
- ¬_ : ∀ {u} → Set u → Set u
- ¬ x = x → ⊥
- infixl 2 ¬_
- data Associativity : Set where
- left-assoc : Associativity
- right-assoc : Associativity
- non-assoc : Associativity
- data Precedence : Set where
- related : Float → Precedence
- unrelated : Precedence
- data Fixity : Set where
- fixity : Associativity → Precedence → Fixity
- {-# BUILTIN ASSOC Associativity #-}
- {-# BUILTIN ASSOCLEFT left-assoc #-}
- {-# BUILTIN ASSOCRIGHT right-assoc #-}
- {-# BUILTIN ASSOCNON non-assoc #-}
- {-# BUILTIN PRECEDENCE Precedence #-}
- {-# BUILTIN PRECRELATED related #-}
- {-# BUILTIN PRECUNRELATED unrelated #-}
- {-# BUILTIN FIXITY Fixity #-}
- {-# BUILTIN FIXITYFIXITY fixity #-}
- .. _reflection:
- **********
- Reflection
- **********
- Builtin types
- -------------
- Names
- ~~~~~
- The built-in ``QNAME`` type represents quoted names and comes equipped with
- equality, ordering, and a show function.
- ::
- postulate Name : Set
- {-# BUILTIN QNAME Name #-}
- primitive
- primQNameEquality : Name → Name → Bool
- primQNameLess : Name → Name → Bool
- primShowQName : Name → String
- The fixity of a name can also be retrived.
- ::
- primitive
- primQNameFixity : Name → Fixity
- To define a decidable propositional equality with the option
- :option:`--safe`, one can use the conversion to a pair of built-in
- 64-bit machine words
- ::
- primitive
- primQNameToWord64s : Name → Σ Word64 (λ _ → Word64)
- with the injectivity proof in the ``Properties`` module.::
- primitive
- primQNameToWord64sInjective : ∀ a b → primQNameToWord64s a ≡ primQNameToWord64s b → a ≡ b
- Name literals are created using the ``quote`` keyword and can appear both in
- terms and in patterns
- ::
- nameOfNat : Name
- nameOfNat = quote Nat
- isNat : Name → Bool
- isNat (quote Nat) = true
- isNat _ = false
- Note that the name being quoted must be in scope.
- Metavariables
- ~~~~~~~~~~~~~
- Metavariables are represented by the built-in ``AGDAMETA`` type. They have
- primitive equality, ordering, show, and conversion to Nat::
- postulate Meta : Set
- {-# BUILTIN AGDAMETA Meta #-}
- primitive
- primMetaEquality : Meta → Meta → Bool
- primMetaLess : Meta → Meta → Bool
- primShowMeta : Meta → String
- primMetaToNat : Meta → Nat
- Builtin metavariables show up in reflected terms. In ``Properties``, there is a proof of injectivity
- of ``primMetaToNat``
- ::
- primitive
- primMetaToNatInjective : ∀ a b → primMetaToNat a ≡ primMetaToNat b → a ≡ b
- which can be used to define a decidable propositional equality with
- the option :option:`--safe`.
- Literals
- ~~~~~~~~
- Literals are mapped to the built-in ``AGDALITERAL`` datatype. Given the appropriate
- built-in binding for the types ``Nat``, ``Float``, etc, the ``AGDALITERAL`` datatype
- has the following shape::
- data Literal : Set where
- nat : (n : Nat) → Literal
- word64 : (n : Word64) → Literal
- float : (x : Float) → Literal
- char : (c : Char) → Literal
- string : (s : String) → Literal
- name : (x : Name) → Literal
- meta : (x : Meta) → Literal
- {-# BUILTIN AGDALITERAL Literal #-}
- {-# BUILTIN AGDALITNAT nat #-}
- {-# BUILTIN AGDALITWORD64 word64 #-}
- {-# BUILTIN AGDALITFLOAT float #-}
- {-# BUILTIN AGDALITCHAR char #-}
- {-# BUILTIN AGDALITSTRING string #-}
- {-# BUILTIN AGDALITQNAME name #-}
- {-# BUILTIN AGDALITMETA meta #-}
- Arguments
- ~~~~~~~~~
- Arguments can be (visible), {hidden}, or {{instance}}::
- data Visibility : Set where
- visible hidden instance′ : Visibility
- {-# BUILTIN HIDING Visibility #-}
- {-# BUILTIN VISIBLE visible #-}
- {-# BUILTIN HIDDEN hidden #-}
- {-# BUILTIN INSTANCE instance′ #-}
- Arguments can be relevant or irrelevant::
- data Relevance : Set where
- relevant irrelevant : Relevance
- {-# BUILTIN RELEVANCE Relevance #-}
- {-# BUILTIN RELEVANT relevant #-}
- {-# BUILTIN IRRELEVANT irrelevant #-}
- Arguments also have a quantity::
- data Quantity : Set where
- quantity-0 quantity-ω : Quantity
- {-# BUILTIN QUANTITY Quantity #-}
- {-# BUILTIN QUANTITY-0 quantity-0 #-}
- {-# BUILTIN QUANTITY-ω quantity-ω #-}
- Relevance and quantity are combined into a modality::
- data Modality : Set where
- modality : (r : Relevance) (q : Quantity) → Modality
- {-# BUILTIN MODALITY Modality #-}
- {-# BUILTIN MODALITY-CONSTRUCTOR modality #-}
- The visibility and the modality characterise the behaviour of an
- argument::
- data ArgInfo : Set where
- arg-info : (v : Visibility) (m : Modality) → ArgInfo
- data Arg (A : Set) : Set where
- arg : (i : ArgInfo) (x : A) → Arg A
- {-# BUILTIN ARGINFO ArgInfo #-}
- {-# BUILTIN ARGARGINFO arg-info #-}
- {-# BUILTIN ARG Arg #-}
- {-# BUILTIN ARGARG arg #-}
- Name abstraction
- ~~~~~~~~~~~~~~~~
- ::
- data Abs (A : Set) : Set where
- abs : (s : String) (x : A) → Abs A
- {-# BUILTIN ABS Abs #-}
- {-# BUILTIN ABSABS abs #-}
- Terms
- ~~~~~
- Terms, sorts, patterns, and clauses are mutually recursive and mapped
- to the ``AGDATERM``, ``AGDASORT``, ``AGDAPATTERN`` and ``AGDACLAUSE``
- built-ins respectively. Types are simply terms. Terms and patterns use
- de Bruijn indices to represent variables.
- ::
- data Term : Set
- data Sort : Set
- data Pattern : Set
- data Clause : Set
- Type = Term
- Telescope = List (Σ String λ _ → Arg Type)
- data Term where
- var : (x : Nat) (args : List (Arg Term)) → Term
- con : (c : Name) (args : List (Arg Term)) → Term
- def : (f : Name) (args : List (Arg Term)) → Term
- lam : (v : Visibility) (t : Abs Term) → Term
- pat-lam : (cs : List Clause) (args : List (Arg Term)) → Term
- pi : (a : Arg Type) (b : Abs Type) → Term
- agda-sort : (s : Sort) → Term
- lit : (l : Literal) → Term
- meta : (x : Meta) → List (Arg Term) → Term
- unknown : Term -- Treated as '_' when unquoting.
- data Sort where
- set : (t : Term) → Sort -- A Set of a given (possibly neutral) level.
- lit : (n : Nat) → Sort -- A Set of a given concrete level.
- prop : (t : Term) → Sort -- A Prop of a given (possibly neutral) level.
- propLit : (n : Nat) → Sort -- A Prop of a given concrete level.
- inf : (n : Nat) → Sort -- Setωi of a given concrete level i.
- unknown : Sort
- data Pattern where
- con : (c : Name) (ps : List (Arg Pattern)) → Pattern
- dot : (t : Term) → Pattern
- var : (x : Nat ) → Pattern
- lit : (l : Literal) → Pattern
- proj : (f : Name) → Pattern
- absurd : (x : Nat) → Pattern -- Absurd patterns have de Bruijn indices
- data Clause where
- clause : (tel : Telescope) (ps : List (Arg Pattern)) (t : Term) → Clause
- absurd-clause : (tel : Telescope) (ps : List (Arg Pattern)) → Clause
- {-# BUILTIN AGDATERM Term #-}
- {-# BUILTIN AGDASORT Sort #-}
- {-# BUILTIN AGDAPATTERN Pattern #-}
- {-# BUILTIN AGDACLAUSE Clause #-}
- {-# BUILTIN AGDATERMVAR var #-}
- {-# BUILTIN AGDATERMCON con #-}
- {-# BUILTIN AGDATERMDEF def #-}
- {-# BUILTIN AGDATERMMETA meta #-}
- {-# BUILTIN AGDATERMLAM lam #-}
- {-# BUILTIN AGDATERMEXTLAM pat-lam #-}
- {-# BUILTIN AGDATERMPI pi #-}
- {-# BUILTIN AGDATERMSORT agda-sort #-}
- {-# BUILTIN AGDATERMLIT lit #-}
- {-# BUILTIN AGDATERMUNSUPPORTED unknown #-}
- {-# BUILTIN AGDASORTSET set #-}
- {-# BUILTIN AGDASORTLIT lit #-}
- {-# BUILTIN AGDASORTPROP prop #-}
- {-# BUILTIN AGDASORTPROPLIT propLit #-}
- {-# BUILTIN AGDASORTINF inf #-}
- {-# BUILTIN AGDASORTUNSUPPORTED unknown #-}
- {-# BUILTIN AGDAPATCON con #-}
- {-# BUILTIN AGDAPATDOT dot #-}
- {-# BUILTIN AGDAPATVAR var #-}
- {-# BUILTIN AGDAPATLIT lit #-}
- {-# BUILTIN AGDAPATPROJ proj #-}
- {-# BUILTIN AGDAPATABSURD absurd #-}
- {-# BUILTIN AGDACLAUSECLAUSE clause #-}
- {-# BUILTIN AGDACLAUSEABSURD absurd-clause #-}
- Absurd lambdas ``λ ()`` are quoted to extended lambdas with an absurd clause.
- The built-in constructors ``AGDATERMUNSUPPORTED`` and ``AGDASORTUNSUPPORTED``
- are translated to meta variables when unquoting.
- Declarations
- ~~~~~~~~~~~~
- There is a built-in type ``AGDADEFINITION`` representing definitions. Values of
- this type is returned by the ``AGDATCMGETDEFINITION`` built-in :ref:`described
- below <reflection-tc-monad>`.
- ::
- data Definition : Set where
- function : (cs : List Clause) → Definition
- data-type : (pars : Nat) (cs : List Name) → Definition -- parameters and constructors
- record-type : (c : Name) (fs : List (Arg Name)) → -- c: name of record constructor
- Definition -- fs: fields
- data-cons : (d : Name) → Definition -- d: name of data type
- axiom : Definition
- prim-fun : Definition
- {-# BUILTIN AGDADEFINITION Definition #-}
- {-# BUILTIN AGDADEFINITIONFUNDEF function #-}
- {-# BUILTIN AGDADEFINITIONDATADEF data-type #-}
- {-# BUILTIN AGDADEFINITIONRECORDDEF record-type #-}
- {-# BUILTIN AGDADEFINITIONDATACONSTRUCTOR data-cons #-}
- {-# BUILTIN AGDADEFINITIONPOSTULATE axiom #-}
- {-# BUILTIN AGDADEFINITIONPRIMITIVE prim-fun #-}
- Type errors
- ~~~~~~~~~~~
- Type checking computations (see :ref:`below <reflection-tc-monad>`)
- can fail with an error, which is a list of ``ErrorPart``\s. This
- allows metaprograms to generate nice errors without having to
- implement pretty printing for reflected terms.
- ::
- -- Error messages can contain embedded names and terms.
- data ErrorPart : Set where
- strErr : String → ErrorPart
- termErr : Term → ErrorPart
- pattErr : Pattern → ErrorPart
- nameErr : Name → ErrorPart
- {-# BUILTIN AGDAERRORPART ErrorPart #-}
- {-# BUILTIN AGDAERRORPARTSTRING strErr #-}
- {-# BUILTIN AGDAERRORPARTTERM termErr #-}
- {-# BUILTIN AGDAERRORPARTNAME nameErr #-}
- .. _reflection-tc-monad:
- Type checking computations
- ~~~~~~~~~~~~~~~~~~~~~~~~~~
- Metaprograms, i.e. programs that create other programs, run in a built-in type
- checking monad ``TC``::
- postulate
- TC : ∀ {a} → Set a → Set a
- returnTC : ∀ {a} {A : Set a} → A → TC A
- bindTC : ∀ {a b} {A : Set a} {B : Set b} → TC A → (A → TC B) → TC B
- {-# BUILTIN AGDATCM TC #-}
- {-# BUILTIN AGDATCMRETURN returnTC #-}
- {-# BUILTIN AGDATCMBIND bindTC #-}
- The ``TC`` monad provides an interface to the Agda type checker using the
- following primitive operations::
- postulate
- -- Unify two terms, potentially solving metavariables in the process.
- unify : Term → Term → TC ⊤
- -- Throw a type error. Can be caught by catchTC.
- typeError : ∀ {a} {A : Set a} → List ErrorPart → TC A
- -- Block a type checking computation on a metavariable. This will abort
- -- the computation and restart it (from the beginning) when the
- -- metavariable is solved.
- blockOnMeta : ∀ {a} {A : Set a} → Meta → TC A
- -- Prevent current solutions of metavariables from being rolled back in
- -- case 'blockOnMeta' is called.
- commitTC : TC ⊤
- -- Backtrack and try the second argument if the first argument throws a
- -- type error.
- catchTC : ∀ {a} {A : Set a} → TC A → TC A → TC A
- -- Infer the type of a given term
- inferType : Term → TC Type
- -- Check a term against a given type. This may resolve implicit arguments
- -- in the term, so a new refined term is returned. Can be used to create
- -- new metavariables: newMeta t = checkType unknown t
- checkType : Term → Type → TC Term
- -- Compute the normal form of a term.
- normalise : Term → TC Term
- -- Compute the weak head normal form of a term.
- reduce : Term → TC Term
- -- Get the current context. Returns the context in reverse order, so that
- -- it is indexable by deBruijn index. Note that the types in the context are
- -- valid in the rest of the context. To use in the current context they need
- -- to be weakened by 1 + their position in the list.
- getContext : TC Telescope
- -- Extend the current context with a variable of the given type and its name.
- extendContext : ∀ {a} {A : Set a} → String → Arg Type → TC A → TC A
- -- Set the current context. Takes a context telescope entries in
- -- reverse order, as given by `getContext`. Each type should be valid
- -- in the context formed by the remaining elements in the list.
- inContext : ∀ {a} {A : Set a} → Telescope → TC A → TC A
- -- Quote a value, returning the corresponding Term.
- quoteTC : ∀ {a} {A : Set a} → A → TC Term
- -- Unquote a Term, returning the corresponding value.
- unquoteTC : ∀ {a} {A : Set a} → Term → TC A
- -- Quote a value in Setω, returning the corresponding Term
- quoteωTC : ∀ {A : Setω} → A → TC Term
- -- Create a fresh name.
- freshName : String → TC Name
- -- Declare a new function of the given type. The function must be defined
- -- later using 'defineFun'. Takes an Arg Name to allow declaring instances
- -- and irrelevant functions. The Visibility of the Arg must not be hidden.
- declareDef : Arg Name → Type → TC ⊤
- -- Declare a new postulate of the given type. The Visibility of the Arg
- -- must not be hidden. It fails when executed from command-line with --safe
- -- option.
- declarePostulate : Arg Name → Type → TC ⊤
- -- Define a declared function. The function may have been declared using
- -- 'declareDef' or with an explicit type signature in the program.
- defineFun : Name → List Clause → TC ⊤
- -- Get the type of a defined name. Replaces 'primNameType'.
- getType : Name → TC Type
- -- Get the definition of a defined name. Replaces 'primNameDefinition'.
- getDefinition : Name → TC Definition
- -- Check if a name refers to a macro
- isMacro : Name → TC Bool
- -- Change the behaviour of inferType, checkType, quoteTC, getContext
- -- to normalise (or not) their results. The default behaviour is no
- -- normalisation.
- withNormalisation : ∀ {a} {A : Set a} → Bool → TC A → TC A
- -- Prints the third argument to the debug buffer in Emacs
- -- if the verbosity level (set by the -v flag to Agda)
- -- is higher than the second argument. Note that Level 0 and 1 are printed
- -- to the info buffer instead. For instance, giving -v a.b.c:10 enables
- -- printing from debugPrint "a.b.c.d" 10 msg.
- debugPrint : String → Nat → List ErrorPart → TC ⊤
- -- Return the formatted string of the argument using the internal pretty printer.
- formatErrorParts : List ErrorPart → TC String
- -- Only allow reduction of specific definitions while executing the TC computation
- onlyReduceDefs : ∀ {a} {A : Set a} → List Name → TC A → TC A
- -- Don't allow reduction of specific definitions while executing the TC computation
- dontReduceDefs : ∀ {a} {A : Set a} → List Name → TC A → TC A
- -- Makes the following primitives to reconstruct hidden parameters:
- -- getDefinition, normalise, reduce, inferType, checkType and getContext
- withReconstructed : ∀ {a} {A : Set a} → TC A → TC A
- -- Fail if the given computation gives rise to new, unsolved
- -- "blocking" constraints.
- noConstraints : ∀ {a} {A : Set a} → TC A → TC A
- -- Run the given TC action and return the first component. Resets to
- -- the old TC state if the second component is 'false', or keep the
- -- new TC state if it is 'true'.
- runSpeculative : ∀ {a} {A : Set a} → TC (Σ A λ _ → Bool) → TC A
- -- Get a list of all possible instance candidates for the given meta
- -- variable (it does not have to be an instance meta).
- getInstances : Meta → TC (List Term)
- {-# BUILTIN AGDATCMUNIFY unify #-}
- {-# BUILTIN AGDATCMTYPEERROR typeError #-}
- {-# BUILTIN AGDATCMBLOCKONMETA blockOnMeta #-}
- {-# BUILTIN AGDATCMCATCHERROR catchTC #-}
- {-# BUILTIN AGDATCMINFERTYPE inferType #-}
- {-# BUILTIN AGDATCMCHECKTYPE checkType #-}
- {-# BUILTIN AGDATCMNORMALISE normalise #-}
- {-# BUILTIN AGDATCMREDUCE reduce #-}
- {-# BUILTIN AGDATCMGETCONTEXT getContext #-}
- {-# BUILTIN AGDATCMEXTENDCONTEXT extendContext #-}
- {-# BUILTIN AGDATCMINCONTEXT inContext #-}
- {-# BUILTIN AGDATCMQUOTETERM quoteTC #-}
- {-# BUILTIN AGDATCMUNQUOTETERM unquoteTC #-}
- {-# BUILTIN AGDATCMQUOTEOMEGATERM quoteωTC #-}
- {-# BUILTIN AGDATCMFRESHNAME freshName #-}
- {-# BUILTIN AGDATCMDECLAREDEF declareDef #-}
- {-# BUILTIN AGDATCMDECLAREPOSTULATE declarePostulate #-}
- {-# BUILTIN AGDATCMDEFINEFUN defineFun #-}
- {-# BUILTIN AGDATCMGETTYPE getType #-}
- {-# BUILTIN AGDATCMGETDEFINITION getDefinition #-}
- {-# BUILTIN AGDATCMCOMMIT commitTC #-}
- {-# BUILTIN AGDATCMISMACRO isMacro #-}
- {-# BUILTIN AGDATCMWITHNORMALISATION withNormalisation #-}
- {-# BUILTIN AGDATCMDEBUGPRINT debugPrint #-}
- {-# BUILTIN AGDATCMONLYREDUCEDEFS onlyReduceDefs #-}
- {-# BUILTIN AGDATCMDONTREDUCEDEFS dontReduceDefs #-}
- {-# BUILTIN AGDATCMNOCONSTRAINTS noConstraints #-}
- {-# BUILTIN AGDATCMRUNSPECULATIVE runSpeculative #-}
- {-# BUILTIN AGDATCMGETINSTANCES getInstances #-}
- Metaprogramming
- ---------------
- There are three ways to run a metaprogram (``TC`` computation). To run
- a metaprogram in a term position you use a :ref:`macro <macros>`. To
- run metaprograms to create top-level definitions you can use the
- ``unquoteDecl`` and ``unquoteDef`` primitives (see `Unquoting
- Declarations`_).
- .. _macros:
- Macros
- ~~~~~~
- Macros are functions of type ``t₁ → t₂ → .. → Term → TC ⊤`` that are defined in
- a ``macro`` block. The last argument is supplied by the type checker and will
- be the representation of a metavariable that should be instantiated with the
- result of the macro.
- Macro application is guided by the type of the macro, where ``Term`` and
- ``Name`` arguments are quoted before passed to the macro. Arguments of any
- other type are preserved as-is.
- For example, the macro application ``f u v w`` where
- ``f : Term → Name → Bool → Term → TC ⊤`` desugars into:
- .. code-block:: agda
- unquote (f (quoteTerm u) (quote v) w)
- where ``quoteTerm u`` takes a ``u`` of arbitrary type and returns its
- representation in the ``Term`` data type, and ``unquote m`` runs a computation
- in the ``TC`` monad. Specifically, when checking ``unquote m : A`` for some
- type ``A`` the type checker proceeds as follows:
- - Check ``m : Term → TC ⊤``.
- - Create a fresh metavariable ``hole : A``.
- - Let ``qhole : Term`` be the quoted representation of ``hole``.
- - Execute ``m qhole``.
- - Return (the now hopefully instantiated) ``hole``.
- Reflected macro calls are constructed using the ``def`` constructor, so given a
- macro ``g : Term → TC ⊤`` the term ``def (quote g) []`` unquotes to a macro
- call to ``g``.
- .. note::
- The ``quoteTerm`` and ``unquote`` primitives are available in the language,
- but it is recommended to avoid using them in favour of macros.
- Limitations:
- - Macros cannot be recursive. This can be worked around by defining the
- recursive function outside the macro block and have the macro call the
- recursive function.
- Silly example:
- ..
- ::
- module example₁ where
- ::
- macro
- plus-to-times : Term → Term → TC ⊤
- plus-to-times (def (quote _+_) (a ∷ b ∷ [])) hole =
- unify hole (def (quote _*_) (a ∷ b ∷ []))
- plus-to-times v hole = unify hole v
- thm : (a b : Nat) → plus-to-times (a + b) ≡ a * b
- thm a b = refl
- Macros lets you write tactics that can be applied without any syntactic
- overhead. For instance, suppose you have a solver::
- magic : Type → Term
- ..
- ::
- postulate God : (A : Set) → A
- magic t =
- def (quote God)
- (arg (arg-info visible (modality relevant quantity-ω)) t ∷ [])
- that takes a reflected goal and outputs a proof (when successful). You can then
- define the following macro::
- macro
- by-magic : Term → TC ⊤
- by-magic hole =
- bindTC (inferType hole) λ goal →
- unify hole (magic goal)
- This lets you apply the magic tactic as a normal function:
- ..
- ::
- module P≠NP where
- postulate T : Set
- postulate P NP : T
- ::
- thm : ¬ P ≡ NP
- thm = by-magic
- .. _unquoting-declarations:
- Tactic Arguments
- ~~~~~~~~~~~~~~~~
- You can declare tactics to be used to solve a particular implicit argument
- using a ``@(tactic t)`` annotation. The provided tactic should be a term
- ``t : Term → TC ⊤``. For instance,
- ::
- defaultTo : {A : Set} (x : A) → Term → TC ⊤
- defaultTo x hole = bindTC (quoteTC x) (unify hole)
- f : {@(tactic defaultTo true) x : Bool} → Bool
- f {x} = x
- test-f : f ≡ true
- test-f = refl
- At calls to `f`, `defaultTo true` is called on the
- metavariable inserted for `x` if it is not given explicitly.
- The tactic can depend on previous arguments to the function.
- For instance,
- ::
- g : (x : Nat) {@(tactic defaultTo x) y : Nat} → Nat
- g x {y} = x + y
- test-g : g 4 ≡ 8
- test-g = refl
- Record fields can also be annotated with a tactic, allowing them to be
- omitted in constructor applications, record constructions and co-pattern
- matches::
- record Bools : Set where
- constructor mkBools
- field fst : Bool
- @(tactic defaultTo fst) {snd} : Bool
- open Bools
- tt₀ tt₁ tt₂ tt₃ : Bools
- tt₀ = mkBools true {true}
- tt₁ = mkBools true
- tt₂ = record{ fst = true }
- tt₃ .fst = true
- test-tt : tt₁ ∷ tt₂ ∷ tt₃ ∷ [] ≡ tt₀ ∷ tt₀ ∷ tt₀ ∷ []
- test-tt = refl
- Unquoting Declarations
- ~~~~~~~~~~~~~~~~~~~~~~
- While macros let you write metaprograms to create terms, it is also useful to
- be able to create top-level definitions. You can do this from a macro using the
- ``declareDef`` and ``defineFun`` primitives, but there is no way to bring such
- definitions into scope. For this purpose there are two top-level primitives
- ``unquoteDecl`` and ``unquoteDef`` that runs a ``TC`` computation in a
- declaration position. They both have the same form:
- .. code-block:: agda
- unquoteDecl x₁ .. xₙ = m
- unquoteDef x₁ .. xₙ = m
- except that the list of names can be empty for ``unquoteDecl``, but not for
- ``unquoteDef``. In both cases ``m`` should have type ``TC ⊤``. The main
- difference between the two is that ``unquoteDecl`` requires ``m`` to both
- declare (with ``declareDef``) and define (with ``defineFun``) the ``xᵢ``
- whereas ``unquoteDef`` expects the ``xᵢ`` to be already declared. In other
- words, ``unquoteDecl`` brings the ``xᵢ`` into scope, but ``unquoteDef``
- requires them to already be in scope.
- In ``m`` the ``xᵢ`` stand for the names of the functions being defined (i.e.
- ``xᵢ : Name``) rather than the actual functions.
- One advantage of ``unquoteDef`` over ``unquoteDecl`` is that
- ``unquoteDef`` is allowed in mutual blocks, allowing mutually
- recursion between generated definitions and hand-written definitions.
- Example usage:
- ..
- ::
- module unquote-id where
- _>>=_ = bindTC
- _>>_ : ∀ {ℓ} {A : Set ℓ} → TC ⊤ → TC A → TC A
- a >> b = a >>= λ { tt → b }
- ::
- arg′ : {A : Set} → Visibility → A → Arg A
- arg′ v = arg (arg-info v (modality relevant quantity-ω))
- -- Defining: id-name {A} x = x
- defId : (id-name : Name) → TC ⊤
- defId id-name = do
- defineFun id-name
- [ clause
- ( ("A" , arg′ visible (agda-sort (lit 0)))
- ∷ ("x" , arg′ visible (var 0 []))
- ∷ [])
- ( arg′ hidden (var 1)
- ∷ arg′ visible (var 0)
- ∷ [] )
- (var 0 [])
- ]
- id : {A : Set} (x : A) → A
- unquoteDef id = defId id
- mkId : (id-name : Name) → TC ⊤
- mkId id-name = do
- ty ← quoteTC ({A : Set} (x : A) → A)
- declareDef (arg′ visible id-name) ty
- defId id-name
- unquoteDecl id′ = mkId id′
- System Calls
- ~~~~~~~~~~~~
- It is possible to run system calls as part of a metaprogram, using the ``execTC`` builtin. You can use this feature to implement type providers, or to call external solvers. For instance, the following example calls ``/bin/echo`` from Agda:
- .. code-block:: agda
- postulate
- execTC : (exe : String) (args : List String) (stdIn : String)
- → TC (Σ Nat (λ _ → Σ String (λ _ → String)))
- {-# BUILTIN AGDATCMEXEC execTC #-}
- macro
- echo : List String → Term → TC ⊤
- echo args hole = do
- (exitCode , (stdOut , stdErr)) ← execTC "echo" args ""
- unify hole (lit (string stdOut))
- _ : echo ("hello" ∷ "world" ∷ []) ≡ "hello world\n"
- _ = refl
- The ``execTC`` builtin takes three arguments: the basename of the executable (e.g., ``"echo"``), a list of arguments, and the contents of the standard input. It returns a triple, consisting of the exit code (as a natural number), the contents of the standard output, and the contents of the standard error.
- It would be ill-advised to allow Agda to make arbitrary system calls. Hence, the feature must be activated by passing the ``--allow-exec`` option, either on the command-line or using a pragma. (Note that ``--allow-exec`` is incompatible with ``--safe``.) Furthermore, Agda can only call executables which are listed in the list of trusted executables, ``~/.agda/executables``. For instance, to run the example above, you must add ``/bin/echo`` to this file:
- .. code-block:: text
- # contents of ~/.agda/executables
- /bin/echo
- The executable can then be called by passing its basename to ``execTC``, subtracting the ``.exe`` on Windows.
|