DDC/FieldProjections: Difference between revisions
No edit summary |
m (To be deleted if no new content appears...) |
||
(3 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
'''This is outdated information'''. The DDC project has moved to [http://discus-lang.org http://discus-lang.org] | |||
== Data fields == | == Data fields == | ||
When data types are defined using field names, we can use the projection operator <hask>(.)</hask> to select the fields. | When data types are defined using field names, we can use the projection operator <hask>(.)</hask> to select the fields. | ||
Line 62: | Line 66: | ||
As Disciple uses the type of the first argument of <hask>(.)</hask> to decide what projection to use, it needs to be constrained to a data type (not just a type variable). Usually a top level type signature is enough. | As Disciple uses the type of the first argument of <hask>(.)</hask> to decide what projection to use, it needs to be constrained to a data type (not just a type variable). Usually a top level type signature is enough. | ||
Compilation of this function: | |||
<haskell> | <haskell> | ||
getX thing = thing.x | getX thing = thing.x | ||
Line 73: | Line 77: | ||
</pre> | </pre> | ||
as there is | as there is no way of knowing what version of <hask>.x</hask> to use, are we talking about the <hask>.x</hask> from <hask>Vector</hask> or <hask>Location</hask>? | ||
Providing a type signature adds the required constraint. | Providing a type signature adds the required constraint. | ||
Line 81: | Line 85: | ||
getX thing = thing.x | getX thing = thing.x | ||
</haskell> | </haskell> | ||
[[Category:Pages to be removed]] |
Latest revision as of 11:59, 19 April 2021
This is outdated information. The DDC project has moved to http://discus-lang.org
Data fields
When data types are defined using field names, we can use the projection operator (.)
to select the fields.
data Vector
= Vector { x :: Float; y :: Float; }
main ()
= do vec = Vector 3.0 4.0
out vec.x -- prints '3.0'
out vec.y -- prints '4.0'
Custom projections
We can also define our own, custom projections and use (.)
to select them. A project
definition is similar to a regular instance
definition in that it defines a set of functions associated with a particular type (in this case, Vector
). When we use (.)
, its first argument is passed as the first argument to our projection function - and so on.
project Vector where
magnitude :: Vector -> Float
magnitude (Vector x y)
= sqrt (x * x + y * y)
dot :: Vector -> Vector -> Float
dot (Vector x1 y1) (Vector x2 y2)
= x1 * x2 + y1 * y2
main ()
= do ...
out vec.magnitude -- prints '5.0'
out vec.dot (Vector 5.0 6.0) -- prints '39.0'
Projections are type directed
In Disciple we can re-use the same field names in multiple data types, each with different field types. The type system uses the type of the first argument of (.)
to determine what projection function to use. Alternatively, we can use the (&)
operator to specify the projection type manually.
data Location
= Location { x :: String; y :: String; }
main ()
= do ...
loc = Location "over" "there"
out loc.x -- prints 'over'
out $ magnitude&{Vector} vec -- prints '5.0'
Using (&)
, we can also use "projection" functions who's first argument is not of the projection type.
project Vector where
...
new :: Float -> Float -> Vector
new posX posY = Vector posX posY
main ()
= do ...
vec2 = new&{Vector} 5.0 6.0
Ambiguous projections
As Disciple uses the type of the first argument of (.)
to decide what projection to use, it needs to be constrained to a data type (not just a type variable). Usually a top level type signature is enough.
Compilation of this function:
getX thing = thing.x
will fail with
./Main.ds: ... Ambiguous projection: .x
as there is no way of knowing what version of .x
to use, are we talking about the .x
from Vector
or Location
?
Providing a type signature adds the required constraint.
getx :: Vector -> Float
getX thing = thing.x