4supports the implementation of *Embedded Domain Specific Languages*
5(EDSLs) in several ways [1]_. One way, as we have already seen, is
6through extending ``do`` notation. Another important way is to allow
7extension of the core syntax. In this section we describe two ways of
8extending the syntax: ``syntax`` rules and ``dsl`` notation.
13We have seen ``if...then...else`` expressions, but these are not built
14in. Instead, we can define a function in the prelude as follows (we
15have already seen this function in Section :ref:`sect-lazy`):
19 boolCase : (x:Bool) -> Lazy a -> Lazy a -> a;
20 boolCase True t e = t;
21 boolCase False t e = e;
23and then extend the core syntax with a ``syntax`` declaration:
27 syntax "if" [test] "then" [t] "else" [e] = boolCase test t e;
29The left hand side of a ``syntax`` declaration describes the syntax
30rule, and the right hand side describes its expansion. The syntax rule
33- **Keywords** — here, ``if``, ``then`` and ``else``, which must be
36- **Non-terminals** — included in square brackets, ``[test]``, ``[t]``
37 and ``[e]`` here, which stand for arbitrary expressions. To avoid
38 parsing ambiguities, these expressions cannot use syntax extensions
39 at the top level (though they can be used in parentheses).
41- **Names** — included in braces, which stand for names which may be
42 bound on the right hand side.
44- **Symbols** — included in quotations marks, e.g. ``:=``. This can
45 also be used to include reserved words in syntax rules, such as
48The limitations on the form of a syntax rule are that it must include
49at least one symbol or keyword, and there must be no repeated
50variables standing for non-terminals. Any expression can be used, but
51if there are two non-terminals in a row in a rule, only simple
52expressions may be used (that is, variables, constants, or bracketed
53expressions). Rules can use previously defined rules, but may not be
54recursive. The following syntax extensions would therefore be valid:
58 syntax [var] ":=" [val] = Assign var val;
59 syntax [test] "?" [t] ":" [e] = if test then t else e;
60 syntax "select" [x] "from" [t] "where" [w] = SelectWhere x t w;
61 syntax "select" [x] "from" [t] = Select x t;
63Syntax macros can be further restricted to apply only in patterns (i.e.,
64only on the left hand side of a pattern match clause) or only in terms
65(i.e. everywhere but the left hand side of a pattern match clause) by
66being marked as ``pattern`` or ``term`` syntax rules. For example, we
67might define an interval as follows, with a static check that the lower
68bound is below the upper bound using ``so``:
72 data Interval : Type where
73 MkInterval : (lower : Float) -> (upper : Float) ->
74 so (lower < upper) -> Interval
76We can define a syntax which, in patterns, always matches ``oh`` for
77the proof argument, and in terms requires a proof term to be provided:
81 pattern syntax "[" [x] "..." [y] "]" = MkInterval x y oh
82 term syntax "[" [x] "..." [y] "]" = MkInterval x y ?bounds_lemma
84In terms, the syntax ``[x...y]`` will generate a proof obligation
85``bounds_lemma`` (possibly renamed).
87Finally, syntax rules may be used to introduce alternative binding
88forms. For example, a ``for`` loop binds a variable on each iteration:
92 syntax "for" {x} "in" [xs] ":" [body] = forLoop xs (\x => body)
95 main = do for x in [1..10]:
96 putStrLn ("Number " ++ show x)
99Note that we have used the ``{x}`` form to state that ``x`` represents
100a bound variable, substituted on the right hand side. We have also put
101``in`` in quotation marks since it is already a reserved word.
106The well-typed interpreter in Section :ref:`sect-interp` is a simple
107example of a common programming pattern with dependent types. Namely:
108describe an *object language* and its type system with dependent types
109to guarantee that only well-typed programs can be represented, then
110program using that representation. Using this approach we can, for
111example, write programs for serialising binary data [2]_ or running
112concurrent processes safely [3]_.
114Unfortunately, the form of object language programs makes it rather
115hard to program this way in practice. Recall the factorial program in
120 fact : Expr G (TyFun TyInt TyInt)
121 fact = Lam (If (Op (==) (Var Stop) (Val 0))
122 (Val 1) (Op (*) (app fact (Op (-) (Var Stop) (Val 1)))
125Since this is a particularly useful pattern, Idris provides syntax
126overloading [1]_ to make it easier to program in such object
131 mkLam : TTName -> Expr (t::g) t' -> Expr g (TyFun t t')
132 mkLam _ body = Lam body
140A ``dsl`` block describes how each syntactic construct is represented
141in an object language. Here, in the ``expr`` language, any variable is
142translated to the ``Var`` constructor, using ``Pop`` and ``Stop`` to
143construct the de Bruijn index (i.e., to count how many bindings since
144the variable itself was bound); and any lambda is translated to a
145``Lam`` constructor. The ``mkLam`` function simply ignores its first
146argument, which is the name that the user chose for the variable. It
147is also possible to overload ``let`` and dependent function syntax
148(``pi``) in this way. We can now write ``fact`` as follows:
152 fact : Expr G (TyFun TyInt TyInt)
153 fact = expr (\x => If (Op (==) x (Val 0))
154 (Val 1) (Op (*) (app fact (Op (-) x (Val 1))) x))
156In this new version, ``expr`` declares that the next expression will
157be overloaded. We can take this further, using idiom brackets, by
162 (<$>) : (f : Lazy (Expr G (TyFun a t))) -> Expr G a -> Expr G t
165 pure : Expr G a -> Expr G a
168Note that there is no need for these to be part of an instance of
169``Applicative``, since idiom bracket notation translates directly to
170the names ``<*>`` and ``pure``, and ad-hoc type-directed overloading
171is allowed. We can now say:
175 fact : Expr G (TyFun TyInt TyInt)
176 fact = expr (\x => If (Op (==) x (Val 0))
177 (Val 1) (Op (*) [| fact (Op (-) x (Val 1)) |] x))
179With some more ad-hoc overloading and type class instances, and a new
180syntax rule, we can even go as far as:
184 syntax "IF" [x] "THEN" [t] "ELSE" [e] = If x t e
186 fact : Expr G (TyFun TyInt TyInt)
187 fact = expr (\x => IF x == 0 THEN 1 ELSE [| fact (x - 1) |] * x)
190.. [1] Edwin Brady and Kevin Hammond. 2012. Resource-Safe systems
191 programming with embedded domain specific languages. In
192 Proceedings of the 14th international conference on Practical
193 Aspects of Declarative Languages (PADL'12), Claudio Russo and
194 Neng-Fa Zhou (Eds.). Springer-Verlag, Berlin, Heidelberg,
195 242-257. DOI=10.1007/978-3-642-27694-1_18
196 http://dx.doi.org/10.1007/978-3-642-27694-1_18
198.. [2] Edwin C. Brady. 2011. IDRIS ---: systems programming meets full
199 dependent types. In Proceedings of the 5th ACM workshop on
200 Programming languages meets program verification (PLPV
201 '11). ACM, New York, NY, USA,
202 43-54. DOI=10.1145/1929529.1929536
203 http://doi.acm.org/10.1145/1929529.1929536
205.. [3] Edwin Brady and Kevin Hammond. 2010. Correct-by-Construction
206 Concurrency: Using Dependent Types to Verify Implementations of
207 Effectful Resource Usage Protocols. Fundam. Inf. 102, 2 (April
208 2010), 145-176. http://dl.acm.org/citation.cfm?id=1883636
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list