123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- ..
- ::
- module language.mixfix-operators where
- data Bool : Set where
- true : Bool
- false : Bool
- data _≡_ {A : Set} : (a b : A) → Set where
- refl : {a : A} → a ≡ a
- infix 4 _≡_
- module M where
- postulate _∙_ : Bool → Bool → Bool
- .. _mixfix-operators:
- ****************
- Mixfix Operators
- ****************
- A type name, function name, or constructor name can comprise one or more name
- parts if we separate them with underscore characters ``_``, and the
- resulting name can be used as an operator. From left to right, each argument
- goes in the place of each underscore ``_``.
- For instance, we can join with underscores the name parts ``if``, ``then``,
- and ``else`` into a single name ``if_then_else_``. The application of the
- function name ``if_then_else_`` to some arguments named ``x``, ``y``, and ``z``
- can still be written as:
- * a standard application by using the full name ``if_then_else_ x y z``
- * an operator application by placing the arguments between the name parts
- ``if x then y else z``, leaving a space between arguments and part names
- * other *sections* of the full name, for instance leaving one or two underscores:
- * ``(if_then y else z) x``
- * ``(if x then_else z) y``
- * ``if x then y else_ z``
- * ``if x then_else_ y z``
- * ``if_then y else_ x z``
- * ``(if_then_else z) x y``
- Examples of type names, function names, and constructor names as mixfix
- operators:
- ::
- -- Example type name _⇒_
- _⇒_ : Bool → Bool → Bool
- true ⇒ b = b
- false ⇒ _ = true
- -- Example function name _and_
- _and_ : Bool → Bool → Bool
- true and x = x
- false and _ = false
- -- Example function name if_then_else_
- if_then_else_ : {A : Set} → Bool → A → A → A
- if true then x else y = x
- if false then x else y = y
- -- Example constructor name _∷_
- data List (A : Set) : Set where
- nil : List A
- _∷_ : A → List A → List A
- .. _precedence:
- Precedence
- ==========
- Consider the expression ``true and false ⇒ false``.
- Depending on which of ``_and_`` and ``_⇒_`` has more precedence,
- it can either be read as ``(false and true) ⇒ false = true``,
- or as ``false and (true ⇒ false) = true``.
- Each operator is associated to a precedence, which is a floating point number
- (can be negative and fractional!).
- The default precedence for an operator is 20.
- .. note::
- Please note that ``->`` is directly handled in the parser. As a result, the
- precedence of ``->`` is lower than any precedence you may declare with
- ``infixl`` and ``infixr``.
- If we give ``_and_`` more precedence than ``_⇒_``, then we will get the first result::
- infix 30 _and_
- -- infix 20 _⇒_ (default)
- p-and : {x y z : Bool} → x and y ⇒ z ≡ (x and y) ⇒ z
- p-and = refl
- e-and : false and true ⇒ false ≡ true
- e-and = refl
- But, if we declare a new operator ``_and’_``
- and give it less precedence than
- ``_⇒_``, then we will get the second result::
- _and’_ : Bool → Bool → Bool
- _and’_ = _and_
- infix 15 _and’_
- -- infix 20 _⇒_ (default)
- p-⇒ : {x y z : Bool} → x and’ y ⇒ z ≡ x and’ (y ⇒ z)
- p-⇒ = refl
- e-⇒ : false and’ true ⇒ false ≡ false
- e-⇒ = refl
- Fixities can be changed when importing with a ``renaming`` directive::
- open M using (_∙_)
- open M renaming (_∙_ to infixl 10 _*_)
- This code brings two instances of the operator ``_∙_`` in scope:
- * the first named ``_∙_`` and with its original fixity
- * the second named ``_*_`` and with the fixity changed to act like a
- left associative operator of precedence 10.
- .. _associativity:
- Associativity
- =============
- Consider the expression ``true ⇒ false ⇒ false``. Depending on whether ``_⇒_``
- associates to the left or to the right, it can be read as
- ``(false ⇒ true) ⇒ false = false``, or ``false ⇒ (true ⇒ false) = true``,
- respectively.
- If we declare an operator ``_⇒_`` as ``infixr``, it will associate to the right::
- infixr 20 _⇒_
- p-right : {x y z : Bool} → x ⇒ y ⇒ z ≡ x ⇒ (y ⇒ z)
- p-right = refl
- e-right : false ⇒ true ⇒ false ≡ true
- e-right = refl
- If we declare an operator ``_⇒’_`` as ``infixl``, it will associate to the left::
- infixl 20 _⇒’_
- _⇒’_ : Bool → Bool → Bool
- _⇒’_ = _⇒_
- p-left : {x y z : Bool} → x ⇒’ y ⇒’ z ≡ (x ⇒’ y) ⇒’ z
- p-left = refl
- e-left : false ⇒’ true ⇒’ false ≡ false
- e-left = refl
- Ambiguity and Scope
- ===================
- If you have not yet declared the fixity of an operator, Agda will
- complain if you try to use ambiguously:
- .. code-block:: agda
- e-ambiguous : Bool
- e-ambiguous = true ⇒ true ⇒ true
- .. code-block:: none
- Could not parse the application true ⇒ true ⇒ true
- Operators used in the grammar:
- ⇒ (infix operator, level 20)
- Fixity declarations may appear anywhere in a module that other
- declarations may appear. They then apply to the entire scope in which
- they appear (i.e. before and after, but not outside).
- Operators in telescopes
- =======================
- Agda does not yet support declaring the fixity of operators declared in
- telescopes, see `Issue #1235 <https://github.com/agda/agda/issues/1235>`.
- However, the following hack currently works:
- .. code-block:: agda
- module _ {A : Set} (_+_ : A → A → A) (let infixl 5 _+_; _+_ = _+_) where
|