# Changes between Initial Version and Version 1 of Language/Overview/FieldProjections

Show
Ignore:
Timestamp:
06/17/10 02:13:14 (5 years ago)
Comment:

--

Unmodified
Removed
Modified
• ## Language/Overview/FieldProjections

v1 v1
1= Field Projections =
3
4When data types are defined using field names, we can use the projection operator `(.)` to select the fields.
5
6{{{
7data Vector
8         = Vector { x :: Float; y :: Float; }
9
10main ()
11 = do   vec = Vector 3.0 4.0
12        putStrLn \$ show vec.x          -- prints '3.0'
13        putStrLn \$ show vec.y          -- prints '4.0'
14}}}
15
16== Custom projections ==
17We can also define our own, custom projections and use `(.)` to select them. A `project` definition is similar to Haskell style `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.
18
19{{{
20project Vector where
21        magnitude :: Vector -> Float
22        magnitude (Vector x y)
23         = sqrt (x * x + y * y)
24
25        dot :: Vector -> Vector -> Float
26        dot (Vector x1 y1) (Vector x2 y2)
27         = x1 * x2 + y1 * y2
28
29main ()
30 = do   ...
31        putStrLn \$ show vec.magnitude               -- prints '5.0'
32        putStrLn vec.dot (Vector 5.0 6.0)    -- prints '39.0'
33}}}
34
35== Projections are type directed ==
36In 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.
37
38{{{
39data Location
40        = Location { x :: String; y :: String; }
41
42main ()
43 = do   ...
44        loc = Location "over" "there"
45        putStr \$ show loc.x                      -- prints 'over'
46
47        putStr \$ show \$ magnitude&{Vector} vec   -- prints '5.0'
48}}}
49
50Using `(&)`, we can also define "projection" functions who's first argument is not of the projection type.
51
52{{{
53project Vector where
54        ...
55        new :: Float -> Float -> Vector
56        new posX posY = Vector posX posY
57
58main ()
59 = do   ...
60        vec2  = new&{Vector} 5.0 6.0
61        ...
62}}}
63
64== Ambiguous projections ==
65As 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.
66
67Compilation of this function:
68{{{
69getX thing = thing.x
70}}}
71
72will fail with
73{{{
74    ./Main.ds: ...
75        Ambiguous projection: .x
76}}}
77
78as there is no way of knowing what version of `.x` to use, are we talking about the `.x` from `Vector` or `Location`?
79
80Providing a type signature adds the required constraint.
81
82{{{
83getx :: Vector -> Float
84getX thing = thing.x
85}}}