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

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

--

Legend:

Unmodified
Added
Removed
Modified
  • Language/Overview/FieldProjections

    v1 v1  
     1= Field Projections = 
     2[http://trac.haskell.org/ddc/wiki/Language/Overview < Overview] 
     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}}}