# Difference between revisions of "DDC/FieldProjections"

m |
|||

Line 73: | Line 73: | ||

</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. |

## Revision as of 10:06, 20 March 2008

## 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
```