Changes between Version 6 and Version 7 of Records/DeclaredOverloadedRecordFields


Ignore:
Timestamp:
Feb 17, 2012 11:29:51 PM (2 years ago)
Author:
guest
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Records/DeclaredOverloadedRecordFields

    v6 v7  
    77 * ''' DORF -- Application Programmer's view '''     (this page) 
    88 * ''' [wiki:Records/DeclaredOverloadedRecordFields/ImplementorsView DORF -- Implementor's view] ''' 
    9  * ''' [wiki:Records/DeclaredOverloadedRecordFields/CompareSORF DORF -- Comparison to SORF] ''' 
    10  * ''' Dot as Postfix Funcion Apply '''   (optional syntactic sugar) 
     9 * ''' [wiki:Records/DeclaredOverloadedRecordFields/COmpareSORF DORF -- Comparison to SORF] ''' 
     10 * ''' [wiki:Records/DeclaredOverloadedRecordFields/DotPostfix Dot as Postfix Funcion Apply] '''   ('''''optional''''' syntactic sugar) 
    1111 
    1212 
     
    197197 
    198198 
    199 --------------- Dot as Postfix Function Apply -------------------- 
    200 --------------- Exploiting the power of the dot -- or not? ------- 
    201199 
    202 Currently (in Haskell 98), declaring a record field generates a field selector function, for example: 
    203  
    204     data Rec = Rec { f :: String }   -- generates: 
    205     f :: Rec -> String 
    206  
    207 And f is 'just a function', to be applied in prefix form. 
    208  
    209 The DORF Overloaded Record Fields proposal also generates field selectors as 'just functions' (to be overloaded for all the record types thay appear in). 
    210  
    211 As with TDNR, I propose an additional syntactic form r.f for selecting field f from record r (of type Rec). The dynamic syntax is simply reverse application r.f <===> (f r)  (So for overloaded field selectors, we use usual type-directed instance resolution.) 
    212  
    213 But dot notation must be written with no spaces around the dot -- because it has strange syntactic properties that mean it isn't 'just an operator'. 
    214  
    215 The reasoning for using dot is exactly as SPJ adumbrates in TDNR ("it is critical to support dot notation") -- essentially, it's standard practice (both for selecting fields from records in data manipulation languages such as SQL, and selecting methods from objects on OO languages). Postfix application supports an object -> action pattern of thinking: focus on the object, then apply some action; or the UNIX pipes concept of the data 'flowing' left to right. 
    216  
    217 The dot syntax is to be optional (and is orthogonal to DORF -- you can use DORF purely pre-fix). (There are voiciferous calls from some on the discussion thread not to use dot syntax, and/or not to use postfix function application. I'd rather get DORF adopted, so I don't want to get into a confrontation over lexical syntax.) 
    218  
    219 Suggested compiler flag ‑XDotPostfixFuncApply. 
    220  
    221 The syntax could use some other character than dot (hash # has been suggested), but there's a danger that is already a user-defined operator in existing code (or in some unrelated GHC extension). There are good syntactic reasons for using dot (see below), besides that it is a convention familiar from other programming paradigms. 
    222  
    223 Note this proposal differs significantly from others for dot syntax, such as: 
    224 http://hackage.haskell.org/trac/haskell-prime/wiki/TypeDirectedNameResolution (TDNR) 
    225 http://hackage.haskell.org/trac/ghc/wiki/Records/DotOperator 
    226  
    227 Dot notation can be used for any function, not just record fields (as with TDNR, but different to SORF). This supports pseudo- or virtual fields. The declaration: 
    228  
    229     fullName r = r.firstName ++ " " ++ r.lastName   -- SPJ's example 
    230  
    231 creates fullName as just a function, not a field. But we can still use dot syntax, and here are some other similar examples: 
    232  
    233     customer.fullName 
    234     shape.area            -- also from SPJ 
    235     date.dayOfWeek        -- not a field: calculated from the date 
    236     name.middleInitial    -- extract from the name field 
    237     tuple.fst             -- Prelude functions 
    238     list.head 
    239     list.length 
    240  
    241 That is, we can use this syntax to 'select' attributes or properties from structures. (Because these are 'virtual', there is no update function.) 
    242  
    243 Dot notation's "strange syntactic properties" 
    244  
    245 Dot Apply must bind tighter than function application. This is unlike any other operator. We want: 
    246  
    247     map toUpper customer.lastName 
    248     ===> map toUpper (lastName customer) 
    249  
    250     m.lookup key                  -- method `lookup' from object m 
    251     ===> (lookup m) key 
    252  
    253 Postfix dots can be stacked up, and bind leftwards: 
    254  
    255     shape.position.xCoord 
    256     ===>  (shape.position).xCoord     -- not! shape.(position.xCoord) 
    257     ===> (xCoord (position shape)) 
    258  
    259 But to facilitate postfix style, there are occasions where we want a loose binding form. We could of course use parentheses, but the requirement is just like loose-binding prefix function application provided by Prelude ($). Suggested operator: 
    260  
    261     (.$) = flip ($) 
    262  
    263 (This is an ordinary Haskell operator, but this proposal is asking to reserve the namespace.) 
    264  
    265 Two examples adapted from SPJ's TDNR wiki, and avoiding the 'something odd' he notices: 
    266  
    267        m.lookup key 
    268     .$ snd 
    269     .$ reverse 
    270  
    271     record.list .$ reverse 
    272                 .$ filter isEven 
    273                 .$ map double 
    274                 .$ foldr (+) 0       -- sum 
    275                 .$ (^ 2)             -- square 
    276           
    277  
    278 Using Dot notation amongst qualified names 
    279  
    280 This must be valid (note no embedded spaces): 
    281     MyData.customer.Their.Module.fullName.Prelude.head.Data.Char.toUpper 
    282  
    283 The syntax rule is: 
    284     A name to the left of a dot starting upper case is a module, 
    285     and the dot binds most tightly. 
    286     A name to the left starting lower case is postfix apply, 
    287     and binds less tightly, but tighter than usual function apply. 
    288     A name at the rightmost end starting upper case is valid, 
    289     it must be a data constructor. 
    290     You can use parentheses to override the binding. 
    291     (And parens would be needed where embedding a data constructor.) 
    292  
    293 Why no embedded spaces? -- And a code-breaking change 
    294  
    295 In case anybody's worrying about parsing the long dotted block above, this is already valid Haskell 98: 
    296  
    297     Data.Char.toUpper.Prelude.head.Prelude.tail 
    298  
    299 "It graphically appeals to the notion of a function composed of several functions", according to a poster resistant to dot as postfix function apply. 
    300  
    301 (Applying the "function" to "hello" yields 'E'.) This is equivalent: 
    302  
    303     Data.Char.toUpper . Prelude.head . Prelude.tail 
    304  
    305 That is, there's already a dot operator (function composition), so the 'good syntactic reason' (per above) for using dot as postfix function apply is that we can be sure it's already reserved as Haskell syntax. 
    306  
    307 The code-breaking change is: 
    308  
    309     Function composition will only work when 
    310     the dot is surrounded by spaces. 
    311  
    312     Dot with no space either side is to change 
    313     to mean postfix function application (tight-binding). 
    314  
    315     Dot with space one side only is to change 
    316     to be invalid syntax -- it's too confusing to assume what's meant. 
    317  
    318 Note that if 'one-sided' dot were valid as partial application of postfix notation (section style): 
    319  
    320     (.f)  ===> (\r -> r.f)          -- eta-expand 
    321           ===> (\r -> (f r))        -- desugar the dot 
    322           ===> f                    -- eta-reduce 
    323  
    324 So map (.f) ts would mean map f ts. 
    325  
    326     (r.) -- makes no sense as a section, as SPJ points out. 
    327  
    328 If you really, really want a section: 
    329  
    330     (.$ f) 
    331     (r .$) 
    332  
    333  
    334  
    335  
    336 There has been lengthy discussion about the interaction of dot syntax and record/field selection -- see the thread starting: 
    337 http://www.haskell.org/pipermail/haskell-cafe/2012-January/098899.html 
    338  
    339  
    340  
    341 Thank you for everybody's contributions, they've significantly tuned the proposal as it went along. 
    342  
    343 Relationship to the proposal for Declared Overloaded Record Fields (DORF) 
    344  
    345 I've concluded that dot notation is controversial (contrary to SPJ's assumption when TDNR started). 
    346  
    347 So to repeat: DORF does not rely on postfix dot notation, neither does postfix dot notation rely on DORF. 
    348  
    349 They're related because DORF relies on field selectors being functions; and field selection being function application -- for which postifx dot provides familiar syntax. (That is, familiar from other programming paradigms.) 
    350