mirror of
https://github.com/edwinb/Idris2-boot.git
synced 2024-11-24 12:54:28 +03:00
Add reference for the dot record syntax.
This commit is contained in:
parent
f44d384d63
commit
eb5af61ebf
@ -18,3 +18,4 @@ This is a placeholder, to get set up with readthedocs.
|
|||||||
|
|
||||||
packages
|
packages
|
||||||
envvars
|
envvars
|
||||||
|
records
|
||||||
|
191
docs/source/reference/records.rst
Normal file
191
docs/source/reference/records.rst
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
Dot syntax for records
|
||||||
|
======================
|
||||||
|
|
||||||
|
.. role:: idris(code)
|
||||||
|
:language: idris
|
||||||
|
|
||||||
|
Long story short, ``.field`` is a postfix projection operator that binds
|
||||||
|
tighter than function application.
|
||||||
|
|
||||||
|
Lexical structure
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
* ``.foo`` is a valid name, which stands for record fields (new ``Name``
|
||||||
|
constructor ``RF "foo"``)
|
||||||
|
|
||||||
|
* ``Foo.bar.baz`` starting with uppercase ``F`` is one lexeme, a namespaced
|
||||||
|
identifier: ``NSIdent ["baz", "bar", "Foo"]``
|
||||||
|
|
||||||
|
* ``foo.bar.baz`` starting with lowercase ``f`` is three lexemes: ``foo``,
|
||||||
|
``.bar``, ``.baz``
|
||||||
|
|
||||||
|
* ``.foo.bar.baz`` is three lexemes: ``.foo``, ``.bar``, ``.baz``
|
||||||
|
|
||||||
|
* If you want ``Constructor.field``, you have to write ``(Constructor).field``.
|
||||||
|
|
||||||
|
* All module names must start with an uppercase letter.
|
||||||
|
|
||||||
|
New syntax of ``simpleExpr``
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Expressions binding tighter than application (``simpleExpr``), such as variables or parenthesised expressions, have been renamed to ``simplerExpr``, and an extra layer of syntax has been inserted.
|
||||||
|
|
||||||
|
.. code-block:: idris
|
||||||
|
|
||||||
|
simpleExpr ::= (.field)+ -- parses as PRecordProjection
|
||||||
|
| simplerExpr (.field)+ -- parses as PRecordFieldAccess
|
||||||
|
| simplerExpr -- (parses as whatever it used to)
|
||||||
|
|
||||||
|
* ``(.foo)`` is a name, so you can use it to e.g. define a function called
|
||||||
|
``.foo`` (see ``.squared`` below)
|
||||||
|
|
||||||
|
* ``(.foo.bar)`` is a parenthesised expression
|
||||||
|
|
||||||
|
Desugaring rules
|
||||||
|
----------------
|
||||||
|
|
||||||
|
* ``(.field1 .field2 .field3)`` desugars to ``(\x => .field3 (.field2 (.field1
|
||||||
|
x)))``
|
||||||
|
|
||||||
|
* ``(simpleExpr .field1 .field2 .field3)`` desugars to ``((.field .field2
|
||||||
|
.field3) simpleExpr)``
|
||||||
|
|
||||||
|
Record elaboration
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* there is a new pragma ``%undotted_record_projections``, which is ``on`` by
|
||||||
|
default
|
||||||
|
|
||||||
|
* for every field ``f`` of a record ``R``, we get:
|
||||||
|
|
||||||
|
* projection ``f`` in namespace ``R`` (exactly like now), unless
|
||||||
|
``%undotted_record_projections`` is ``off``
|
||||||
|
|
||||||
|
* projection ``.f`` in namespace ``R`` with the same definition
|
||||||
|
|
||||||
|
Example code
|
||||||
|
------------
|
||||||
|
|
||||||
|
.. code-block:: idris
|
||||||
|
|
||||||
|
record Point where
|
||||||
|
constructor MkPoint
|
||||||
|
x : Double
|
||||||
|
y : Double
|
||||||
|
|
||||||
|
This record creates two projections:
|
||||||
|
* ``.x : Point -> Double``
|
||||||
|
* ``.y : Point -> Double``
|
||||||
|
|
||||||
|
Because ``%undotted_record_projections`` are ``on`` by default, we also get:
|
||||||
|
* ``x : Point -> Double``
|
||||||
|
* ``y : Point -> Double``
|
||||||
|
|
||||||
|
To prevent cluttering the ordinary global name space with short identifiers, we can do this:
|
||||||
|
|
||||||
|
.. code-block:: idris
|
||||||
|
|
||||||
|
%undotted_record_projections off
|
||||||
|
|
||||||
|
record Rect where
|
||||||
|
constructor MkRect
|
||||||
|
topLeft : Point
|
||||||
|
bottomRight : Point
|
||||||
|
|
||||||
|
For ``Rect``, we don't get the undotted projections:
|
||||||
|
|
||||||
|
.. code-block:: idris
|
||||||
|
|
||||||
|
Main> :t topLeft
|
||||||
|
(interactive):1:4--1:11:Undefined name topLeft
|
||||||
|
Main> :t .topLeft
|
||||||
|
\{rec:0} => .topLeft rec : ?_ -> Point
|
||||||
|
|
||||||
|
Let's define some constants:
|
||||||
|
|
||||||
|
.. code-block:: idris
|
||||||
|
|
||||||
|
pt : Point
|
||||||
|
pt = MkPoint 4.2 6.6
|
||||||
|
|
||||||
|
rect : Rect
|
||||||
|
rect =
|
||||||
|
MkRect
|
||||||
|
(MkPoint 1.1 2.5)
|
||||||
|
(MkPoint 4.3 6.3)
|
||||||
|
|
||||||
|
User-defined projections work, too. (Should they?)
|
||||||
|
|
||||||
|
.. code-block:: idris
|
||||||
|
|
||||||
|
(.squared) : Double -> Double
|
||||||
|
(.squared) x = x * x
|
||||||
|
|
||||||
|
Finally, the examples:
|
||||||
|
|
||||||
|
.. code-block:: idris
|
||||||
|
|
||||||
|
main : IO ()
|
||||||
|
main = do
|
||||||
|
-- desugars to (.x pt)
|
||||||
|
-- prints 4.2
|
||||||
|
printLn $ pt.x
|
||||||
|
|
||||||
|
-- prints 4.2, too
|
||||||
|
-- maybe we want to make this a parse error?
|
||||||
|
printLn $ pt .x
|
||||||
|
|
||||||
|
-- prints 10.8
|
||||||
|
printLn $ pt.x + pt.y
|
||||||
|
|
||||||
|
-- works fine with namespacing
|
||||||
|
-- prints 4.2
|
||||||
|
printLn $ (Main.pt).x
|
||||||
|
|
||||||
|
-- the LHS can be an arbitrary expression
|
||||||
|
-- prints 4.2
|
||||||
|
printLn $ (MkPoint pt.y pt.x).y
|
||||||
|
|
||||||
|
-- user-defined projection
|
||||||
|
-- prints 17.64
|
||||||
|
printLn $ pt.x.squared
|
||||||
|
|
||||||
|
-- prints [1.0, 3.0]
|
||||||
|
printLn $ map (.x) [MkPoint 1 2, MkPoint 3 4]
|
||||||
|
|
||||||
|
-- .topLeft.y desugars to (\x => .y (.topLeft x))
|
||||||
|
-- prints [2.5, 2.5]
|
||||||
|
printLn $ map (.topLeft.y) [rect, rect]
|
||||||
|
|
||||||
|
-- desugars to (.topLeft.x rect + .bottomRight.y rect)
|
||||||
|
-- prints 7.4
|
||||||
|
printLn $ rect.topLeft.x + rect.bottomRight.y
|
||||||
|
|
||||||
|
-- qualified names work, too
|
||||||
|
-- all these print 4.2
|
||||||
|
printLn $ Main.Point.(.x) pt
|
||||||
|
printLn $ Point.(.x) pt
|
||||||
|
printLn $ (.x) pt
|
||||||
|
printLn $ .x pt
|
||||||
|
|
||||||
|
-- haskell-style projections work, too
|
||||||
|
printLn $ Main.Point.x pt
|
||||||
|
printLn $ Point.x pt
|
||||||
|
printLn $ (x) pt
|
||||||
|
printLn $ x pt
|
||||||
|
|
||||||
|
-- record update syntax uses dots now
|
||||||
|
-- prints 3.0
|
||||||
|
printLn $ (record { topLeft.x = 3 } rect).topLeft.x
|
||||||
|
|
||||||
|
-- prints 2.1
|
||||||
|
printLn $ (record { topLeft.x $= (+1) } rect).topLeft.x
|
||||||
|
|
||||||
|
Parses but does not typecheck:
|
||||||
|
|
||||||
|
.. code-block:: idris
|
||||||
|
|
||||||
|
-- parses as: map.x [MkPoint 1 2, MkPoint 3 4]
|
||||||
|
-- maybe we should disallow spaces before dots?
|
||||||
|
--
|
||||||
|
printLn $ map .x [MkPoint 1 2, MkPoint 3 4]
|
Loading…
Reference in New Issue
Block a user