Frege has built-in mechanism to access and mutate (non-destructive) record fields.
Consider the following type in Frege:
1 2 3 4 5 |
|
Now we can use the following functions to get and set record fields:
1 2 3 4 5 6 7 8 |
|
For Field x
,
- The function
Point.x
is the getter. - The function
Point.{x = }
is a setter which sets the fieldx
with a new value. - The function
Point.{x <- }
is also a setter but applies a function to update the current value.
We can use the functions like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Frege also provides some shortcuts to apply these functions:
1 2 3 4 5 6 7 8 9 10 11 |
|
Multiple updates can be combined:
1 2 |
|
Accessors and updates can be at any level deep. Let’s create another type:
1 2 3 4 5 6 7 8 9 10 |
|
Here we have an aggregate type Circle
which composes another type Point
for it’s field center
.
Now we can update and select fields at different levels:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
In the latest version, Frege provides syntactic sugar for lambdas using underscores. For example, T.foo
can be written
as _.foo
if the type can be deduced from the context the lambda is applied. Hence the following two are equivalent.
1 2 3 4 5 |
|
Frege provides another utility to check for a field’s existence. This would be useful if we have multiple constructors with different set of fields.
1 2 3 4 5 6 7 8 9 10 11 |
|
In the above code, we have two constructors Point2d
and Point3d
where the field z
exists only for Point3d
.
We can check for the existence of field z
like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
For more details on how these field existence check, accessor and mutator functions are generated for a record type, here is the link to Frege language reference: http://www.frege-lang.org/doc/Language.pdf.
Happy coding!