= Field Projections = [http://trac.haskell.org/ddc/wiki/Language/Overview < Overview] 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 putStrLn $ show vec.x -- prints '3.0' putStrLn $ show 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 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. {{{ 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 ... putStrLn $ show vec.magnitude -- prints '5.0' putStrLn 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" putStr $ show loc.x -- prints 'over' putStr $ show $ magnitude&{Vector} vec -- prints '5.0' }}} Using `(&)`, we can also define "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 }}}