Changes between Version 6 and Version 7 of Records/DeclaredOverloadedRecordFields


Ignore:
Timestamp:
Feb 17, 2012 11:29:51 PM (4 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