Quantcast

Some thoughts on Type-Directed Name Resolution

classic Classic list List threaded Threaded
65 messages Options
1234
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Some thoughts on Type-Directed Name Resolution

Steve Horne
There's a proposal at the moment to add support for TDNR to Haskell - to leverage "the power of the dot" (e.g. for intellisense).

http://hackage.haskell.org/trac/haskell-prime/wiki/TypeDirectedNameResolution

I approve of the goal, but I'd like to suggest a different approach.

My basic idea is stolen from Bertrand Meyer (Object-Oriented Software Construction, second edition). Basically, a class *is* both a module and a type. Quote...

  Classes as modules

  Object orientation is primarily an architectural technique: its major effect is on the
  modular structure of software systems.

  The key role here is again played by classes. A class describes not just a type of
  objects but also a modular unit. In a pure object-oriented approach:

           Classes should be the only modules.

By the logic of equivalence relations, we can conclude that a type *is* a module. Only I'd adapt that a little. In C++, the following operators can all be used to access the "module" for some type or value...

  • ::   Scope resolution
  • .    Member dereference
  • ->   Member dereference via a pointer
  • .*   Member-pointer dereference
  • ->*  Member-pointer dereference via a pointer
In C++, a type and an instance each have their own modules. A (smart) pointer has its own module, separate from the module for the type it points to. And member-pointers exist because sometimes there's a need to reference a member without knowing or (yet) caring which instance.

We already have member pointers - the functions that map an instance to the field value. It would make some sense if these could be placed in a module associated with the type (not the instance).

When an instance is created of a type, that can effectively (without run-time overhead) create a new module associated with the new instance. This will contain the same field-access functions, but with the instance parameter already curried in.

So there's no real need for any new meaning of the . operator - it's just access to names within a module. And there's no need for a new mechanism for accessing fields - only for a way to place them in that module scope, and a little sugar that gives us the same field-access function but with the instance parameter already curried in.

Once we have these modules containing compiler-generated field-access functions, though, it makes some sense to allow additional functions (and perhaps types) to be added within that types module explicitly by the programmer. It may also make sense to allow functions to be explicitly defined which will be added to the instance-modules and support the prefix-instance-parameter sugar.

Finally, as with C++, when dealing with IORef and similar, it make make sense to have a separate -> operator (spelled differently, of course). Or it could use the standard dot. C++ and D disagree in this (in C++, the smart pointer has its own module separate from the pointed-at instance - in D, there is no -> or equivalent).

As an aside, Ada has already gone through a related transition. The original Ada 83 had variant records, but no "true classes". In Ada 95, "tagged types" were added which were like variant records, but which supported inheritance and run-time dispatch. The discriminant is replaced by a "tag" which is presumably implemented as a virtual table pointer. However, functions and procedures weren't members. The typical call of a "method" would be...

    packagename.procedure_name ( instance_arg, other_args );

Ada 2005 added some workarounds to allow conventional OOP call notation. See section 1.3 of the Ada 2005 rationale for details. However, it all feels a bit kludgy. In particular, the procedures and functions still aren't members - there are just some special rules for when they can be used as if they were. I've not actually used Ada 2005, but I'd bet some confusion can result from that.

Personally, I think Meyer was at least partly right - if types (and instances) are modules, the kludge-factor is much lower. C++ actually doesn't get this quite right IMO (you can access static class members through the instance objects, for example, not just through the classes), but C++ classes *do* act mostly like modules and that is a very useful trait - particularly within the declarative sublanguage (templates etc).


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Some thoughts on Type-Directed Name Resolution

AntC
Steve Horne <sh006d3592 <at> blueyonder.co.uk> writes:

>
>     There's a proposal at the moment to add support for TDNR to Haskell
>     - to leverage "the power of the dot" (e.g. for
intellisense).http://hackage.haskell.org/trac/haskell-
prime/wiki/TypeDirectedNameResolution
>     I approve of the goal, ...

Steve, I think that proposal has been rather superseeded by
http://hackage.haskell.org/trac/ghc/wiki/Records/OverloadedRecordFields, which
draws on TDNR. But SORF is best seen as an evolving design space, with precise
details yet to be clarified/agreed. I've put my own variation into the ring:
http://www.haskell.org/pipermail/glasgow-haskell-users/2011-
December/021298.html     -- which seems to have fallen into a black hole :-(

One of the aspects of TDNR that wasn't so popular was that its type-directed
resolution was very similar to instance resolution, but subtly and confusingly
different.

I guess we have to be very careful about the dot. It seems to be in a
very 'crowded' syntax space, so if we implement the wrong way, we could end up
shutting the door with the keys left inside.

SPJ's observations about how the dot works in other languages are all good
points. He's arguing that the dot should behave in a familiar way. I'm most
used to it in SQL as table.column, but I guess for most programmers it's
object.method. Haskell is already encumbered by Module.name, and g . f
(function composition with spaces round the dot).

I like the part in OverloadedRecordFields (and TDNR) re user-defined 'virtual'
fields. (fullName being a concatenation of the datatype fields firstName and
lastName, area being a calculation over a Shape datatype.) But the point about
those being virtual is that they're not first-class fields: you can't update
through them. SPJ got 'stuck' at that point.

My proposal was that restricting the dot to field selection wasted too much of
the design space. Instead dot should be merely syntactic sugar for reverse
function application. That is:
       whatever.funcmethod ==> (funcmethod whatever)
(Note no spaces around the dot. This is syntactically distinct from qualified
names because the name to the left of the dot begins lower-case.)

Then funcmethod can be a 'real' field selector, or a virtual field or a class
method or some other function completely.

So to get to name resolution: since dot is (reverse) function application, we
can use all the usual Haskell type inference/instance selection 'for free'.
Either/both `whatever' and `funcmethod' could be arguments passed through from
a distant call, which turned out to be a record type and field selector (not
recognisable as such from its name). So we'd get polymorphic record and field
selection 'for free'.

I'd also like to be able to mix the dot with qualified names:
       A.b.(C.D.e.f).G.h ==> (G.h ((f C.D.e) A.b))
The syntax rule is: an upper-case name to the left of the dot means this is a
qualified name, and binds most tightly. lower-case to the left means reverse-
function applic. Of course you can use parentheses to group differently.

(Re a one-sided dot I have no intuitions. TDNR includes some options for
partial application/sections, SORF some more. They seem to me what Wirth would
call 'rococo'. If dot is to be merely function application, it hardly seems
worth worrying about.)

How do we get field names to be suitable funcmethods for dot applying to
records? And how do we support field update? ==> Subjects for a different post.

There's also an elephant in the room I haven't talked about: TDNR started with
what happens inside an IDE when you type `x.' and all the possible methods (or
fields) for x pop up. This follows the philosophy in OO of focus on the
object -> look for the action. (Same thinking as right-click in GUI's.
Contrast old-style 'green screen' applications where you went down a menu tree
first (action), then looked for your object.)

If the dot is merely function application, then what follows the dot could
be 'anything' (including very generic functions like show or return). I plain
don't know if IDE's can be smart enough to spot that what's to the left of the
dot is a datatype and offer its fields, or get from its type to its instances
to their methods. (Actually, under my proposal, datatype to fields is exactly
datatype to Has instance.) (How) could it tell what are more-specific or more-
generic methods?


>     My basic idea is stolen from Bertrand Meyer (Object-Oriented
>     Software Construction, second edition). Basically, a class *is* both
>     a module and a type. ...

1) Are you sure that C++ classes/instances/methods are comparable enough to
Haskell's? This is a very confusing area of terminology for object-oriented
cp. functional languages.

2) Have you looked at GHC 7.4.1 innovations around classes-as-types and
Constraint kinds?




_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Some thoughts on Type-Directed Name Resolution

paul r-2

AntC> Steve, I think that proposal has been rather superseeded by
AntC> http://hackage.haskell.org/trac/ghc/wiki/Records/OverloadedRecordFields, which
AntC> draws on TDNR. But SORF is best seen as an evolving design space, with precise
AntC> details yet to be clarified/agreed. I've put my own variation into the ring:
AntC> http://www.haskell.org/pipermail/glasgow-haskell-users/2011-
AntC> December/021298.html     -- which seems to have fallen into a black hole :-(

AntC> One of the aspects of TDNR that wasn't so popular was that its type-directed
AntC> resolution was very similar to instance resolution, but subtly and confusingly
AntC> different.

AntC> I guess we have to be very careful about the dot. It seems to be in a
AntC> very 'crowded' syntax space, so if we implement the wrong way, we could end up
AntC> shutting the door with the keys left inside.

AntC> (...)

All this dot syntax magic frankly frightens me. Haskell, as a pure
functionnal language, requires (and allows !) a programming style that
just does not mix well with object oriented practices. Stretching the
syntax to have the dot feel a-bit-but-not-really like object oriented
programming, mainly to have IDE autocompletion on some cases, does not
make much sens.

If the editor matters - and it probably does -, we could rather take
a more ambitious path, and work on a real semantic editor, as opposed to
a plain left-to-right text editor, with hacked semantic goodies to
alleviate the pain.

Indeed, very often in haskell, we just don't think code left to right,
or top to bottom. Emacs ability to move point quickly certainly helps,
but I'd surely welcome a drastic switch, to something allowing us to
work directly on type-checked syntax trees.


--
  Paul

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Some thoughts on Type-Directed Name Resolution

Steve Horne
On 28/01/2012 13:00, Paul R wrote:

> AntC>  Steve, I think that proposal has been rather superseeded by
> AntC>  http://hackage.haskell.org/trac/ghc/wiki/Records/OverloadedRecordFields, which
> AntC>  draws on TDNR. But SORF is best seen as an evolving design space, with precise
> AntC>  details yet to be clarified/agreed. I've put my own variation into the ring:
> AntC>  http://www.haskell.org/pipermail/glasgow-haskell-users/2011-
> AntC>  December/021298.html     -- which seems to have fallen into a black hole :-(
>
> AntC>  One of the aspects of TDNR that wasn't so popular was that its type-directed
> AntC>  resolution was very similar to instance resolution, but subtly and confusingly
> AntC>  different.
>
> AntC>  I guess we have to be very careful about the dot. It seems to be in a
> AntC>  very 'crowded' syntax space, so if we implement the wrong way, we could end up
> AntC>  shutting the door with the keys left inside.
>
> AntC>  (...)
>
> All this dot syntax magic frankly frightens me. Haskell, as a pure
> functionnal language, requires (and allows !) a programming style that
> just does not mix well with object oriented practices. Stretching the
> syntax to have the dot feel a-bit-but-not-really like object oriented
> programming, mainly to have IDE autocompletion on some cases, does not
> make much sens.
That's a benefit of my idea. Modular programming used the dot long
before OOP became popular - OOP stole the dot from modular programming!
If a record is a module, that only means that one thing can be both a
module and a type (or value) at the same time. It takes little from OOP
that OOP didn't already take from the more fundamental modular
programming - and Haskell already has modules.

> If the editor matters - and it probably does -, we could rather take
> a more ambitious path, and work on a real semantic editor, as opposed to
> a plain left-to-right text editor, with hacked semantic goodies to
> alleviate the pain.
Every programmer has their own favorite editor, usually using the same
one to work in many different languages. For the moment, you'd have a
hard job separating me from Notepad++.

If you really want a "semantic editor", I'd argue a rich visual language
with a file format that isn't intended to be read directly. Something
more like writing in Word than writing in TeX. But I don't think most
programmers are ready for this, for various reasons. Version control
tools and readable differences get a place near the top of that list.


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Some thoughts on Type-Directed Name Resolution

Steve Horne
On 30/01/2012 04:23, Steve Horne wrote:

> On 28/01/2012 13:00, Paul R wrote:
>> AntC>  Steve, I think that proposal has been rather superseeded by
>> AntC>  
>> http://hackage.haskell.org/trac/ghc/wiki/Records/OverloadedRecordFields,
>> which
>> AntC>  draws on TDNR. But SORF is best seen as an evolving design
>> space, with precise
>> AntC>  details yet to be clarified/agreed. I've put my own variation
>> into the ring:
>> AntC>  http://www.haskell.org/pipermail/glasgow-haskell-users/2011-
>> AntC>  December/021298.html     -- which seems to have fallen into a
>> black hole :-(
>>
>> AntC>  One of the aspects of TDNR that wasn't so popular was that its
>> type-directed
>> AntC>  resolution was very similar to instance resolution, but subtly
>> and confusingly
>> AntC>  different.
>>
>> AntC>  I guess we have to be very careful about the dot. It seems to
>> be in a
>> AntC>  very 'crowded' syntax space, so if we implement the wrong way,
>> we could end up
>> AntC>  shutting the door with the keys left inside.
>>
>> AntC>  (...)
>>
>> All this dot syntax magic frankly frightens me. Haskell, as a pure
>> functionnal language, requires (and allows !) a programming style that
>> just does not mix well with object oriented practices. Stretching the
>> syntax to have the dot feel a-bit-but-not-really like object oriented
>> programming, mainly to have IDE autocompletion on some cases, does not
>> make much sens.
> That's a benefit of my idea. Modular programming used the dot long
> before OOP became popular - OOP stole the dot from modular
> programming! If a record is a module, that only means that one thing
> can be both a module and a type (or value) at the same time. It takes
> little from OOP that OOP didn't already take from the more fundamental
> modular programming - and Haskell already has modules.
>
Sorry for replying to myself - I just thought I could explain this better.

I'm basically asserting that a record in standard Pascal (without any of
that OOP Turbo Pascal 5.5+/Delphi stuff) is a module. It doesn't matter
that the only names that can be held in that module are field names -
it's still a container of named items and therefore a special case of a
module.

In the Pascal case (like C structs), the content of the module doesn't
include functions or methods or whatever, it only includes fields. And
the module is only accessible via the record instances, not via the
record type (there's nothing like C++ member pointers).

Converting this to Haskell - well, we already use field-access
functions, so why not move those to the record-instance module instead
of having them pollute some existing namespace?

Since naming the same thing twice (once to identify the module, once to
specify the instance parameter) would be annoying, why not auto-curry
that parameter? The result is still a function living in a module.

And rather than lose the original function, why not move that to another
scope - a module that's associated with the record type rather than the
record instance? If you don't specify an instance, you can't curry that
parameter - it still makes sense.

There's no inheritance here, no virtual functions, no OOP features at
all - just Pascal-like records adapted for immutability by supplying a
field access function rather than e.g. a field offset. The function
placed in the record-type module would be the exact same function we get
now, just in a different scope.

However, once you have the idea that a record is a module, maybe it
makes sense to put some other functions in there too? As a minimal
solution no, but it's nice to know there's room for future expansion.

There's nothing OOP about this at all - it's really just adapting and
extending what standard Pascal does. You could extend it to include OOP
if you really wanted to, but the minimal solution just moves the
existing Haskell access functions to another scope, and adds a
pre-curried version in a further scope, associating those scopes with
the record type and record instances respectively.


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Some thoughts on Type-Directed Name Resolution

Donn Cave-4
In reply to this post by Steve Horne
On 28/01/2012 13:00, Paul R wrote:
...
> All this dot syntax magic frankly frightens me. Haskell, as a pure
> functionnal language, requires (and allows !) a programming style that
> just does not mix well with object oriented practices. Stretching the
> syntax to have the dot feel a-bit-but-not-really like object oriented
> programming, mainly to have IDE autocompletion on some cases, does not
> make much sens.

In the glasgow-haskell-users discussion, it has been pointed out (to
little apparent effect) that the current notation for access by field
name, `field record', is naturally functional and is easier to read
for a functionally trained eye than a postfix `record.field' alternative.
It isn't so much of an issue for OO programmers because the languages
are also procedural and the expressions tend to be simpler.  In a
language like Haskell, an expression could switch back and forth several
times between pre-fix (functional) and post-fix (dot) notation.  Like,
`yolk (separate (crack (largeEnd egg)))' becomes
`(separate (crack (egg.smallEnd))).yolk'

That elementary example doesn't give me much trouble, but it sure
doesn't seem to be much of an improvement in notational elegance.
See how natural the transformation with function composition -

yolk (separate (crack (largeEnd egg)))
yolk ((separate . crack . largeEnd) egg)
yolk (f egg) where f = separate . crack . largeEnd

... compared to the re-shuffing necessary with post-fix dot notation
(assuming for the sake of discussion a functional dot notation
 .field = \ r -> r.field)

(separate (crack (egg.smallEnd))).yolk
((separate . crack . .smallEnd) egg).yolk
(f egg).yolk where f = separate . crack . .smallEnd

        Donn

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Some thoughts on Type-Directed Name Resolution

Steve Horne
On 30/01/2012 07:09, Donn Cave wrote:
> ((separate . crack . .smallEnd) egg).yolk
> (f egg).yolk where f = separate . crack . .smallEnd

Scary - that ".smallEnd" worries me. It's like a field is being
referenced with some magical context from nowhere.

Obviously I need to read that full proposal.

Sorry for going on about it, but this wouldn't happen in my idea. If
field access functions are just items in a module, the . separates the
module identification from the item name, same as always. The only
difference is how you identify the module. There's no special
interactions with function composition, or whatever it is that's
happening here. If you want to composite the function with some other
function without knowing in advance which record value you're dealing
with, just get the access function from the record-type module.

If I'm correctly guessing what your code means, that reads as...

(f egg).yolk where f = separate . crack . (eggModule.eggType.smallEnd)

OK, in a sense specifying "eggModule.eggType" there is a bit redundant,
but in general that isn't true - define f separately and it needs some
clue for the type inference to decide where to look for "smallEnd", and
"eggtype" provides it. I'd prefer a notation that allows me to reference
the field without needing type inference to determine which record type
it relates to.

But then again, I'm probably just not understanding the reason behind
that wierdness - perhaps it wouldn't seem so wierd if I did. Or maybe
it's just a familiarity issue.

First thought - I've not addressed access from within a polymorphic
function with type class constraints. The situation there would (without
extra features) be the same as it is now, with no TDNR support. Field
access functions would have to be provided as explicit operations within
the type class.

That said, it shouldn't be hard to handle. For example, a type class can
explicitly state which field names it is interested in, and an instance
can provide functions to access those fields. Alternatively, the
instance might support using arbitrary functions (of the right type).
This might allow some wierdness (fields that aren't really fields), but
it may allow some useful flexibility (this particular type provides the
field "daddy", that type provides "mummy", a third type has no named
fields but has a function that works by pattern matching that can
provide the positionally-defined field - either way, this type class
will refer to "parent") so that polymorphic functions can use the dot
notation, but the relationship between fields in the type class and
fields in the instance type are flexible. It's really just syntactic
sugar for what type classes have to do now - providing a dot notation,
but still using vtable references to field access functions to do the work.


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Some thoughts on Type-Directed Name Resolution

paul r-2
In reply to this post by Steve Horne
Steve> Every programmer has their own favorite editor, usually using the same
Steve> one to work in many different languages. For the moment, you'd have
Steve> a hard job separating me from Notepad++.

Main editors have very advanced customization features (though
incredibly hacky most of the time). A type-directed (this word is what
I like most in the proposal ;]) Haskell editing mode for them could be
a good first step.

Steve> If you really want a "semantic editor", I'd argue a rich visual
Steve> language with a file format that isn't intended to be read directly.
Steve> Something more like writing in Word than writing in TeX. But I don't
Steve> think most programmers are ready for this, for various reasons.
Steve> Version control tools and readable differences get a place near the
Steve> top of that list.

Well, in the long term I don't know ... maybe plain text won't be a good
representation of a program anymore. But in the short term that's not an
option. However, I see no problem in just constructing this textual
representation through a strictly type-directed (yeah!) syntax tree
editor.

Emacs, Vim, and a lot of others have "snippet" support. The workflow
could be something like :

  - action to create a new top-level function

  - PROMPT : name  (eg. map)
  - PROMPT : signature  (eg.  (a -> b) -> [a] -> [b])
  - PROMPT : parameters matching (eg. f (x:xs))

  - a stub is inserted with name, signature, and "undefined" definition
      map :: (a -> b) -> [a] -> [b]
      map f (x:xs) = undefined
      map f [] = undefined

  - now enters definition construction. You would start by adding to
    a 'pool' the bindings you want to combine. Some could be added to
    the pool automatically (function parameters, top-level definitions
    in the module, explicitly imported functions ...). Then you would
    pick one of them, and the type-directed system would offer
    type-correct completion. For example :

      - The pool state is { f :: a -> b , x :: a, xs :: [a],
                            map :: (a -> b) -> [a] -> [b] }
        (the type variables scope over the entire pool)

      - The definition type must be [b]

      - I ask to use 'f'. It isn't [b] so I can't use it alone. The
        wonderful system would then reduce the pool to things that I can
        combine f with in order to keep the target [b] type. The result
        is { map f xs :: [b] }. I say ok.

      - The sub is now :
          map :: (a -> b) -> [a] -> [b]
          map f (x:xs) = map f xs
          map f [] = undefined

      - Now I ask to use (:) :: c -> [c] -> [c] . They are plenty of
        places where it could be used in the definition, so let's narrow
        the choice by associating the 'c' type to something in our
        expression : c == b. So (:) :: b -> [b] -> [b]

      - we have no expression typing as 'b' in the definition, but we
        have a single expression that types as [b], and it is 'map
        f xs'. So the system can safely offer :
          map :: (a -> b) -> [a] -> [b]
          map f (x:xs) = undefined : map f xs
          map f [] = undefined

      - now let's define the first 'undefined'. Its type is b. We ask
        this time to use the 'x' binding (x :: a). But we are looking
        for a 'b'. We have f :: a -> b so the system can offer 'f x'.

          map :: (a -> b) -> [a] -> [b]
          map f (x:xs) = f x : map f xs
          map f [] = undefined

      - The last undefined is trivial.


The user interface would certainly matter much, to have a fast and
pleasant experience. But the point is that as a pure language, haskell
very looks well suited for this kind of incremental syntax-tree editing,
with type-directed assistance. I wonder, even, if some rules could be
defined to construct automatically a definition that typechecks and use
all bindings in the pool :)

Back to the point of the thread, it looks like we certainly can target
type-directed editing with current haskell function notation, which has
the advantage of being beautiful and consistent.

--
  Paul

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Some thoughts on Type-Directed Name Resolution

Donn Cave-4
In reply to this post by Steve Horne
Quoth Steve Horne <[hidden email]>,
> On 30/01/2012 07:09, Donn Cave wrote:

>> ((separate . crack . .smallEnd) egg).yolk
>> (f egg).yolk where f = separate . crack . .smallEnd
>
> Scary - that ".smallEnd" worries me. It's like a field is being
> referenced with some magical context from nowhere.
>
> Obviously I need to read that full proposal.

As I said:
> (assuming for the sake of discussion a functional dot notation
>  .field = \ r -> r.field)

By that, I meant to say that I just made that up.  I am sure that
various proposals have made some notational provision for `\ r -> r.field',
but it may or may not be `.field', I don't recall.

But that's all the magic there is to it.  Either you have a notational
shorthand for it, or you're obliged to write out `\ r -> r.field'

        Donn

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Some thoughts on Type-Directed Name Resolution

AntC
In reply to this post by Donn Cave-4
Donn Cave <donn <at> avvanta.com> writes:

>
> On 28/01/2012 13:00, Paul R wrote:
> ...
> > All this dot syntax magic frankly frightens me. Haskell, as a pure
> > functionnal language, requires (and allows !) a programming style that
> > just does not mix well with object oriented practices.
>
> In the glasgow-haskell-users discussion, it has been pointed out (to
> little apparent effect) that the current notation for access by field
> name, `field record', is naturally functional and is easier to read
> for a functionally trained eye than a postfix `record.field' alternative.
> [snip]
> Donn
>
Donn, I can see the argument "Haskell has never been afraid to be different.
Just because OO does it like that, so what?"

But if you read SPJ's discussion in the TDNR proposal, there's "a cultural
connection to OO". My post at the head of this thread put it as "focus on the
object -> look for the action".

Of course it's easy to 'fake' postfix function application:
    (.$) = flip ($)

But the trouble is that .$ binds weakly. What we want is for the dot to bind
tighter even than function apply. So:
     crack egg.largeEnd   ==> crack (largeEnd egg)
(Where ==> means 'is syntactic sugar for'.)

We're already familiar with the tight-binding dot for qualified names. I
suppose we're coping with the visual confusion with space-surrounded dot as
function composition.

But I can see that "one more petit bonbon" could tip confusion over the edge.

To my eye, one-sided dot application is a bonbon too far.

My proposal is that field selection functions be just ordinary functions, and
dot notation be just function application(tight-binding). Then:
      object.fieldfuncmethod   ==> fieldfuncmethod object
(Subject to the tight binding for the dot.)
And one-sided dot application is pointless (! errk I mean 'without purpose',
no different to writing the bare object or bare fieldfuncmethod).

Then you can write in your familiar style, and can use polymorphic field
selectors as plain functions (same syntax as presently).

Those under the influence of OO can write dot notation, until they discover
the joys of pointless style.

AntC


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Some thoughts on Type-Directed Name Resolution

Donn Cave-4
Quoth AntC <[hidden email]>,
...
> My proposal is that field selection functions be just ordinary functions, and
> dot notation be just function application(tight-binding). Then:
>       object.fieldfuncmethod   ==> fieldfuncmethod object
> (Subject to the tight binding for the dot.)
> And one-sided dot application is pointless (! errk I mean 'without purpose',
> no different to writing the bare object or bare fieldfuncmethod).

That's interesting!  The wiki page on SORF (Simple Overloaded Record Fields,
http://hackage.haskell.org/trac/ghc/wiki/Records/OverloadedRecordFields)
has some language that, as I interpreted it, meant that Has/Get syntactic
sugar depended on the dot, so it's indispensable.  Your proposal actually
has some similar language but, I see you don't mean it that way.  That's
great news for anyone who's really dying to get somewhere with records,
if it means that the functionality could in principle be introduced
independently of changes to the interpretation of "." that would break
a lot of code.

        Donn

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Some thoughts on Type-Directed Name Resolution

AntC
Donn Cave <donn <at> avvanta.com> writes:

>
> Quoth AntC <anthony_clayden <at> clear.net.nz>,
> ...
> > My proposal is that field selection functions be just ordinary functions,
and
> > dot notation be just function application(tight-binding). Then:
> >       object.fieldfuncmethod   ==> fieldfuncmethod object
> > (Subject to the tight binding for the dot.)
> > And one-sided dot application is pointless (! errk I mean 'without
purpose',
> > no different to writing the bare object or bare fieldfuncmethod).
>
> That's interesting!  The wiki page on SORF (Simple Overloaded Record Fields,
> http://hackage.haskell.org/trac/ghc/wiki/Records/OverloadedRecordFields)
> has some language that, as I interpreted it, meant that Has/Get syntactic
> sugar depended on the dot, so it's indispensable.

Yes it does, and that's one of the things I didn't like - hence my counter-
proposal. In particular in SORF, the dot notation got tied into 'virtual
record selectors'. Now 'virtual record selectors' is a good idea, but SORF
tied it to the field selection approach, so had to go via a Has instance,
which introduced a `set' method as well as the get, which didn't make sense,
so SPJ ran into trouble.

Actually the TDNR proposal was better re the "power of the dot": "works with
any function".

As soon as you decide to make 'virtual record selectors' just ordinary
functions (so they select but not update), then you can see that field names
are also just ordinary functions (for selection purposes). So the semantics
for field 'selection' (whether or not you use dot notation) is just function
application. So Type-Directed Name resolution is just instance resolution. So
it all gets much easier.

>  Your proposal actually
> has some similar language but, I see you don't mean it that way.  That's
> great news for anyone who's really dying to get somewhere with records,
> if it means that the functionality could in principle be introduced
> independently of ...

Yes. Actually, (IMHO) the biggest block to making some progress with
the 'cottage industry' for records (and there are heaps of ideas out there) is
that currently the field name appearing in data decls grabs so much of the
namespace real estate. It creates a global name (selector function) that can't
be overloaded.

You'll see in my other posts last night (NZ time) that the first thing I think
should happen is to switch off auto-creation of field selection functions.
(This should have come along as an option with DisambiguateRecordFields, I
think. http://www.haskell.org/pipermail/glasgow-haskell-users/2012-
January/021750.html)

> ... changes to the interpretation of "." that would break
> a lot of code.
>

Yes, in principle we could introduce the semantics for field-selectors-as-
overloaded-functions without introducing any special syntax for field
selection (dot notation or whatever). But the 'Records in Haskell' thread
started with a Reddit/Yesod discussion about records, and the lack of dot
notation being the last major wart in Haskell. "A sentiment open to doubt" in
the words of the poet. It stung SPJ enough to open up the discussion (and I
guess now is timely as 7.4.1 gets put to bed).

For me, the record/field namespacing is the major wart, polymorphism only
slightly less, and the notation is a side-issue. But I don't want to lose the
initiative that's built up, so I'm trying to address both at the same time.

AntC





_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Some thoughts on Type-Directed Name Resolution

Richard A. O'Keefe

On 1/02/2012, at 11:38 AM, AntC wrote:
> As soon as you decide to make 'virtual record selectors' just ordinary
> functions (so they select but not update), then you can see that field names
> are also just ordinary functions (for selection purposes). So the semantics
> for field 'selection' (whether or not you use dot notation) is just function
> application. So Type-Directed Name resolution is just instance resolution. So
> it all gets much easier.

I'm reminded of Pop-2, where f(x) and x.f meant exactly the same thing.
Overloading was a (dynamic) property of f, not a property of dot.

Ada had two reasons for adding dot syntax, and much as I admire Ada,
I'm not sure that I agree with either of them.
One was to be more familiar to programmers from other languages, but
since there remain interesting differences between x.f in Ada and x.f
in other languages, it's not clear to me how much of a kindness that
really is.  The other is that x.f means basically what f(x) would have,
*had f(x) been legal*; the aim was to be able to use methods without
having to important everything from a module.

Now that might have some relevance to Haskell.  Making f x and x.f the
same is pretty appealing, but it is imaginable that the former might
require importing the name of f from a module and the latter might not.
That is to say, it lets f and .f have completely different meanings.
Oh the joy!  Oh the improved readability!  -- on some other planet, maybe.



_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Some thoughts on Type-Directed Name Resolution

AntC
In reply to this post by Steve Horne

> On 1/02/2012, at 11:38 AM, AntC wrote:
> > As soon as you decide to make 'virtual record selectors'
> > just ordinary  functions (so they select but not update)
> > , then you can see that field names  are also just
> ordinary functions (for selection purposes). So the
> > semantics  for field 'selection' (whether or not you use
> > dot notation) is just function  application. So
> Type-Directed Name resolution is just instance resolution.
> > So  it all gets much easier.
>
>
> Richard O'Keefe wrote:
> ...  Making f x
> and x.f the same is pretty appealing, but it is imaginable
> that the former might require importing the name of f from
> a module and the latter might not. That is to say, it lets
> f and .f have completely different meanings. Oh the joy!
> Oh the improved readability!  -- on some other planet,
> maybe.
>
Hi Richard, I'm not sure I understand what you're saying.

I'm proposing x.f is _exactly_ f x. That is, the x.f gets
desugared at an early phase in compilation.
If the one needs importing some name from a module, than so
does the other.

A 'one-sided dot doesn't mean anything. (Also, I feel
vaguely nauseous even seeing it written down.)
Under my proposal, the only thing .f could mean is:
     \z -> z.f
which desugars to
     \z -> f z
which means (by eta-reduction)
      f

And to complete the story: the only thing (x.) could mean
is:
     \g -> x.g
So a use like:
     (x.) f            -- or z f, where z = (x.)
would desugar to
      f x
which is the same as x.f
A use like (x.)f (no spaces around the parens) would amount
to the same thing.


This is all so weird I'm inclined to say that one-sided dot
is probably a syntax error, and reject it. It's too
dangerously ambiguous between the syntax for 'proper' dot
notation and function composition.

Or is there something I'm not understanding?
[Good to see another NZ'er on the list, by the way.]

AntC

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Some thoughts on Type-Directed Name Resolution

quick


On Tue, 31 Jan 2012 23:10:34 -0700, Anthony Clayden  
<[hidden email]> wrote:
> I'm proposing x.f is _exactly_ f x. That is, the x.f gets
> desugared at an early phase in compilation.

Anthony,

I think part of the concern people are expressing here is that the above  
would imply the ability to use point-free style.  But this orthogonality  
is disavowed by your exception:

> A 'one-sided dot doesn't mean anything.

I haven't read the underlying proposals, so I apologize if the following  
is covered, but my understanding of the discussion is that the x.f  
notation is intended to disambiguate f to be a field name of the type of x  
and therefore be advantageous over "f x" notation where f is presently in  
the global namespace.

With your exception, I still cannot disambiguate the following:

data Rec = { foo :: String }

foo :: Rec -> String
foo = show

rs :: [Rec]
rs = [ ... ]

bar = map foo rs

If the exception doesn't exist, then I could write one of the following to  
clarify my intent:

bar = map foo rs
baz = map .foo rs


--
-KQ

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Some thoughts on Type-Directed Name Resolution

AntC
Kevin Quick <quick <at> sparq.org> writes:

>
>
> On Tue, 31 Jan 2012 23:10:34 -0700, Anthony Clayden  
> <anthony_clayden <at> clear.net.nz> wrote:
> > I'm proposing x.f is _exactly_ f x. That is, the x.f gets
> > desugared at an early phase in compilation.
>
> Anthony,
>
> I think part of the concern people are expressing here is that the above  
> would imply the ability to use point-free style.  But this orthogonality  
> is disavowed by your exception:
>
> > A 'one-sided dot doesn't mean anything.
>

Kevin, thank you for helping me clarify my descriptions. I admit my 'proposal'
is probably a bit hard to follow at the moment, because it lives in a series
of emails, rather than all in a coherent wiki page.

It's also possibly confusing because there are three differing proposals in
play, and they all use dot notation for field selection, but they use it
somewhat differently.

But every proposal supports dot-as-function-composition, providing the dot
appears with space on both sides.

The discussion with Donn Cave has clarified that under my proposal (but not
TDNR or SORF), the dot notation is not necessary. Donn is concerned that older
code might be using dot for function composition in contexts that would be
ambiguous with field-selection-as-reverse-application.
 http://www.haskell.org/pipermail/haskell-cafe/2012-January/099008.html

So we could make the dot notation a compiler option:
- you either keep with H98 syntax,
  so field selection must be by usual function syntax f x
- or use dot notation so that x.f desugars to f x
  (of course you could still use f x: nothing forces you to use the dot)

Let me give some examples to clarify what I mean by 'one-sided' dot:
   M.f    -- no spaces, upper case to left, is qualified name
   x.f    -- no spaces, lower case to left, desugars to f x
   x . f  -- spaces both side of dot, is function composition
   x. f   -- space on one side only, what does that mean?
   x .f   -- space on one side only, what does that mean?

In my view, those last two (which I'm calling 'one-sided' dot) are too
confusing (for the eye, at least). I would reject them as invalid syntax. H98
might treat them as function composition. (I'm not sure, I wouldn't code like
that.)

Donn is saying that he doesn't want to break extant code that uses 'one-sided'
dot. Fair enough. Under my proposal we could make it a compiler option to
stick with H98 syntax, an which case x.f is function composition (I believe),
not field selection.

I know Wadler's rule about the disproportionate time spent on lexical syntax.
SPJ was trying (inter alia) to introduce dot notation to support more OO-type
thinking. I'm more familiar with dot-as-field-selector from relational
databases, so I'm keen to introduce it.

But frankly it's a side-show compared to addressing the namespace issues
around records.


> I haven't read the underlying proposals, ...

No, clearly you haven't from what follows. Pay me (and the other contributors)
the respect of doing so before wasting my time. I'm a busy person. I
appreciate the feedback on this forum when it's informed. I appreciate that
people give their time voluntarily (which is what I'm doing).




_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Some thoughts on Type-Directed Name Resolution

quick
Fair deuce.  With all due respect now included, my same concern still seems to
apply although I believe I poorly stated it originally.  Allow me to retry:

  By declaring partial application an invalid parse, it introduces an exception
to point-free style that is at odds with the normal intuition of the uses of "f x".

SPJ's SOPR raises it as an issue and indicates he's inclined to disallow it; my
concern above would still apply.

As I surely mis-understand it (referencing your proposal as RHCT since I haven't
seen another reference):

SOPR:      map (\r -> f r) recs
SOPR:      map (get f) recs
SOPR/alt:  qfmap (undefined :: "f") id recs

RHCT:      map (\r -> f r) recs
RHCT:      map (\r -> r.$rev_ f) recs
RHCT:      map ((.$)f) recs

If partial application is allowed (against SPJ's inclination and explicitly
disallowed in your scheme), I could have:

    map .f recs

in either SOPR or your proposal, which (to me) is an intuitive coordination of
the two concepts (point-free/partial application and f.x desugaring).  I don't
think this is currently a valid parse, so I don't think it breaks existing, but
that's not a very well informed opinion either.

My concern is a triviality however; my intent was to attempt to assist in trying
to clarify a what I perceived as a conceptual gap in the discussion.  I am most
grateful for the significant time and effort contributed by yourself, SPJ, and
all other parties, and I fear I've mostly wasted people's time on syntactic
trivialities already well discussed and dismissed.  Please do carry on, it's all
good stuff.

-KQ


Quoting AntC <[hidden email]>:

> Kevin Quick <quick <at> sparq.org> writes:
>
> >
> >
> > On Tue, 31 Jan 2012 23:10:34 -0700, Anthony Clayden  
> > <anthony_clayden <at> clear.net.nz> wrote:
> > > I'm proposing x.f is _exactly_ f x. That is, the x.f gets
> > > desugared at an early phase in compilation.
> >
> > Anthony,
> >
> > I think part of the concern people are expressing here is that the above  
> > would imply the ability to use point-free style.  But this orthogonality  
> > is disavowed by your exception:
> >
> > > A 'one-sided dot doesn't mean anything.
> >
>
> Kevin, thank you for helping me clarify my descriptions. I admit my
> 'proposal'
> is probably a bit hard to follow at the moment, because it lives in a series
>
> of emails, rather than all in a coherent wiki page.
>
> It's also possibly confusing because there are three differing proposals in
> play, and they all use dot notation for field selection, but they use it
> somewhat differently.
>
> But every proposal supports dot-as-function-composition, providing the dot
> appears with space on both sides.
>
> The discussion with Donn Cave has clarified that under my proposal (but not
> TDNR or SORF), the dot notation is not necessary. Donn is concerned that
> older
> code might be using dot for function composition in contexts that would be
> ambiguous with field-selection-as-reverse-application.
>  http://www.haskell.org/pipermail/haskell-cafe/2012-January/099008.html
>
> So we could make the dot notation a compiler option:
> - you either keep with H98 syntax,
>   so field selection must be by usual function syntax f x
> - or use dot notation so that x.f desugars to f x
>   (of course you could still use f x: nothing forces you to use the dot)
>
> Let me give some examples to clarify what I mean by 'one-sided' dot:
>    M.f    -- no spaces, upper case to left, is qualified name
>    x.f    -- no spaces, lower case to left, desugars to f x
>    x . f  -- spaces both side of dot, is function composition
>    x. f   -- space on one side only, what does that mean?
>    x .f   -- space on one side only, what does that mean?
>
> In my view, those last two (which I'm calling 'one-sided' dot) are too
> confusing (for the eye, at least). I would reject them as invalid syntax. H98
>
> might treat them as function composition. (I'm not sure, I wouldn't code like
>
> that.)
>
> Donn is saying that he doesn't want to break extant code that uses
> 'one-sided'
> dot. Fair enough. Under my proposal we could make it a compiler option to
> stick with H98 syntax, an which case x.f is function composition (I believe),
>
> not field selection.
>
> I know Wadler's rule about the disproportionate time spent on lexical syntax.
>
> SPJ was trying (inter alia) to introduce dot notation to support more OO-type
>
> thinking. I'm more familiar with dot-as-field-selector from relational
> databases, so I'm keen to introduce it.
>
> But frankly it's a side-show compared to addressing the namespace issues
> around records.
>
>
> > I haven't read the underlying proposals, ...
>
> No, clearly you haven't from what follows. Pay me (and the other
> contributors)
> the respect of doing so before wasting my time. I'm a busy person. I
> appreciate the feedback on this forum when it's informed. I appreciate that
> people give their time voluntarily (which is what I'm doing).
>
>
>
>
> _______________________________________________
> Haskell-Cafe mailing list
> [hidden email]
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>




-------------------------------------------------
This mail sent through IMP: http://horde.org/imp/

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Some thoughts on Type-Directed Name Resolution

Evan Laforge
In reply to this post by quick
> I haven't read the underlying proposals, so I apologize if the following is
> covered, but my understanding of the discussion is that the x.f notation is
> intended to disambiguate f to be a field name of the type of x and therefore
> be advantageous over "f x" notation where f is presently in the global
> namespace.

Here's another idea, I'm not sure if this one has come up before: f.x
desugars as M.f x, where 'M' is the module that defines the type of
'x'.  It's an error if 'x' is not monomorphic.

You still can't have the same record name in two different records in
the same module, but this way the record selector is monomorphic, and
it's up to desugaring to find the defining module and if it's imported
(I'd expect an error if not).

However, I'd still want the prefix functional notation so it could be
composed with other functions, and at that point, why have the postfix
dot notation at all?  Just say that '#x' requires a monomorphic
argument, and desugars to 'M.x' where 'M' is the module that the type
of its argument lives in, and combine as normal: (#y . #x) record.
This way it's not even specific to records.

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Some thoughts on Type-Directed Name Resolution

AntC
In reply to this post by quick
 <quick <at> sparq.org> writes:

>
> Fair deuce.  With all due respect now included, my same concern still seems
to
> apply although I believe I poorly stated it originally.  Allow me to retry:
OK, thank you.

>
>   By declaring partial application an invalid parse, it introduces an
exception
> to point-free style that is at odds with the normal intuition of the uses
of "f x".

I'm not (and I don't think any of the other proposals are) trying to declare
partial application as an invalid parse. I'm saying that if you want to part-
apply function composition (in point-free style), you need to be careful with
your syntax, because it's easily confused.

A piece of background which has perhaps been implicit in the discussions up to
now. Currently under H98:
       f.g    -- (both lower case, no space around the dot)
Is taken as function composition -- same as (f . g).
       f.  g  -- is taken as func composition (f . g)
       f  .g  -- is taken as func composition (f . g)

I believe all three forms are deprecated these days, but as Donn points out
there may be code still using it. Part of the reason for deprecating is the
qualified name syntax, which _mustn't_ have dots. So:
       M.f     -- is qualified f from module M
       M. f    -- is dubious, did you mean M.f?
               -- or function composition (M . f)?
               -- with M being a data constructor
       M .f    -- similarly dubious between M.f vs (M . f)
The reason those are dubious is that it's relatively unusual to part-apply a
data constructor in combination with function composition. More likely you've
made a typo. Nevertheless, if that's what you want to do, be careful to code
it as (M . f)

All the proposals in play are going to change the meaning of f.g. Some of the
proposals (not mine) are going to change the meaning of f. and /or .g -- as
Donn points out, any/all of these changes may break code. I say it's better to
be conservative: reject f. and .g as invalid syntax. (If existing code has f.g
as function composition, changing the meaning to field extraction is going to
give a type failure, so it'll be 'in your face'.)

All proposals are saying that if you want to use dot as function composition
you must always put the spaces round the dot (or at least between the dot and
any name) -- even if you're part-applying. So:
      (f .)   -- part-apply function composition on f
      (. g)   -- part-apply function composition
{- as an exercise for the reader: what does that second one mean? How is it
different to the first one? Give an example of use with functions head, tail
and a list. -}

       (f.)   -- I say is ambiguous, did you mean (f .)
              -- or miss out something after the dot ?
       (.f)   -- I say is ambiguous, did you mean (. f)
              -- or miss out something before the dot ?

I'm saying that for both of the above, it's safer to treat them as an invalid
parse, and require a space between the dot and the name.

>
> SPJ's SOPR raises it as an issue and indicates he's inclined to disallow it;
my
> concern above would still apply.

"SOPR"? SPJ's current proposal is abbreviated as "SORF" (Simple Overloaded
Record Fields). His older proposal as "TDNR" (Type-Directed Name Resolution).
http://hackage.haskell.org/trac/ghc/wiki/Records

I don't think either of those disallow partial application of function
composition. I do think they discuss how the syntax could be confusing, so
require you to be careful.


Another piece of background which the discussion is probably not being
explicit about (so thank you for forcing me to think through the explanation):
under H98 record declarations
      data Customer = Customer { customer_id :: Int }
You immediately get a function:
      customer_id :: Customer -> Int
Then you can apply customer_id to a record, to extract the field. Because the
type of customer_id is restricted to exactly one record type, this strengthens
type inference. (Whatever customer_id is applied to must be type Customer, the
result must be type Int.)

For my proposal, I'm trying very hard to be consistent with the H98 style,
except to say that field extractor function f can apply to any record type
(providing it has field f). Specifically, if the f field is always a String,
we can help type inference. The type of f is (approximately speaking):
       f :: (Has r Proxy_f String) => r -> String
Or I prefer SPJ's suggested syntactic sugar:
       f :: r{ f :: String} => r -> String

But type inference for r is now harder: we have to gather information about r
from the type environment where f is applied to r, enough to figure out which
record type it is; then look up the instance declaration (generated from the
data decl) to know how to extract the f field. That much isn't too hard. The
really difficult part is how to do that in such a way that we can also update
f to produce a new r, and cope with all the possible things f might be -
including if f is polymorphic or higher-ranked.

(The "trying hard" is why my Record Update for Higher-ranked or Changing Types
contained such ugly code.)
So I'm trying to support mixing H98 record fields with new-style poly-record
field extractors. If you see in code:
       f r
(And you know already that r is a record and f is a field -- perhaps you're
working in a database application). Then you know we're extracting a field
from a record, whether it's a H98 record or a new-style record. Similarly:
       r.f   -- desugars to f r, so you know just as much

What's more, perhaps you've got new-style records in your module, but you're
importing a H98 record definition from some other module. Then:
       customer_id customer  -- extracts the customer_id from the record
       customer.customer_id  -- means just the same
Wow!! we've just used dot-notation on H98-style records, and we didn't need to
change any code at all in the imported module.

>
> As I surely mis-understand it (referencing your proposal as RHCT since I
haven't
> seen another reference):

You're right that there isn't a name for my proposal, and I definitely need
one. (I take it "RHCT" comes from Record Update for Higher-ranked or Changing
Types. Doesn't quite trip off the tongue, I'd say.) I'm thinking:

    "DORF" -- Declared Overloaded Record Fields
           -- The "ORF" part is similar to SPJ's SORF.
           -- The "Declared" means you have to declare a field,
           -- before using it in a data decl.
           -- Or the "D" might mean "Dictionary-based" as in data dictionary
           --   (not "dictionary" in the sense of "dictionary-passing")


In these examples you're giving, I assume recs is a list of records(?). I
don't understand what you're doing with the "SOPR" items, so I've cut them.
>
> ...

In the "RHCT" examples, I assume r is a record, f is a field (selector
function) -- or is it 'just some function'?, rev_ is a field selector for a
higher-ranked function (to reverse lists of arbitrary type), .$ is the 'fake'
I used to simulate dot-as-field-selector. Thank you for reading all that so
closely.

> RHCT:      map (\r -> f r) recs
is the same as:  map f recs                -- by eta reduction
so map f takes a list of records, returns a list of the f field from each
This also works under H98 record fields, with type enforcement that the
records must be of the single type f comes from.

> RHCT:      map (\r -> r.$rev_ f) recs
Beware that (.$) is an operator, so it binds less tightly than function
application, so it's a poor 'fake' syntactically. Did you mean .$ to simulate
dot-notation to extract field rev_ from r? Then put:
             map (\r -> (r.$rev_) f) recs
This takes the Higher-Ranked reversing function from each record in recs, and
(on the face of it) returns a list obtained by applying it to f. I've assumed
above that f is a field selector function (or 'just some function'). So it's
not a list. So you'll get a type error trying to apply (r.$rev_) to f.

If you meant to apply (r.$rev_) to the f field in r, put:
             map (\r -> (r.$rev_) (r.$f)) recs
For the type to work, this requires the f field to be a list. The map returns
a list of reversed lists from the f field of each record.

> RHCT:      map ((.$)f) recs
If you mean this to return a list of the f fields from recs, put:
             map f recs
I don't know what else you could be trying to do.

>
> If partial application is allowed (against SPJ's inclination and explicitly
> disallowed in your scheme), I could have:
>
>     map .f recs

If you mean this to return a list of the f fields from recs, put:
DORF:          map f recs        -- are you beginning to see how easy this is?

I'm saying the ".f" should be rejected as too confusing.
(That is, under DORF aka RHCT. Under SORF or TDNR I'm not sure, which is why I
don't like their proposals for dot notation, which is why I re-engineered it
so that dot notation is tight-binding reverse function application **and
nothing more**.)

I don't know what else you could be trying to do, but if you're trying to use
dot as function composition (part-applied), put:
             map (. f) recs
But this won't extract an f field from recs (exercise for the reader).

> ... my intent was to attempt to assist in trying
> to clarify a what I perceived as a conceptual gap in the discussion.  I am
most
> grateful for the significant time and effort contributed by yourself, SPJ,
and
> all other parties, and I fear I've mostly wasted people's time on syntactic
> trivialities already well discussed and dismissed.  Please do carry on, it's
all
> good stuff.
>
> -KQ
>

Thank you Kevin, we got there in the end. Your questions did help me clarify
and explain what was implicit.

I think in general that syntax is trivial, but for one thing we've got very
complex syntax already in Haskell. Our 'syntax engineering' has got to be
careful to 'fit in', and not use up too many of the options that are still
available.

What's special with dot syntax is it's well-established and with well-
established (range of) meanings in other programming paradigms. If we
introduce dot-notation into Haskell, we have to try to make it behave like
those paradigms, but in a 'Haskelly' way.

[To go a little off-topic/out of scope. My gold standard is
polymorphic/anonymous records with concatenation, merge, projection,
extension, everything you get in relational algebra. I don't want to use up
all the design options just getting through the current namespace
restrictions -- infuriating though they are.]

AntC



_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Some thoughts on Type-Directed Name Resolution

Richard A. O'Keefe
In reply to this post by AntC

On 1/02/2012, at 7:10 PM, Anthony Clayden wrote:

>
>> On 1/02/2012, at 11:38 AM, AntC wrote:
>>> As soon as you decide to make 'virtual record selectors'
>>> just ordinary  functions (so they select but not update)
>>> , then you can see that field names  are also just
>> ordinary functions (for selection purposes). So the
>>> semantics  for field 'selection' (whether or not you use
>>> dot notation) is just function  application. So
>> Type-Directed Name resolution is just instance resolution.
>>> So  it all gets much easier.
>>
>>
>> Richard O'Keefe wrote:
>> ...  Making f x
>> and x.f the same is pretty appealing, but it is imaginable
>> that the former might require importing the name of f from
>> a module and the latter might not. That is to say, it lets
>> f and .f have completely different meanings. Oh the joy!
>> Oh the improved readability!  -- on some other planet,
>> maybe.
>>
> Hi Richard, I'm not sure I understand what you're saying.

I'm saying that if dot is to do anything at all that it does
not do now, then f x and x.f being identical is sort of OK (
though it does rather clash with f . g), but any differences
between them would be confusing.
>
> This is all so weird I'm inclined to say that one-sided dot
> is probably a syntax error, and reject it.

It wasn't a syntax error, it just wasn't intended to be
Haskell code at all, just an ad hoc English text abbreviation
for "f occurring after a dot".

Of course (x.) = \f -> f x
and       (.f) = \x -> f x
are precisely the kind of sections people will expect to be
legitimate once they've seen (x.f)...

Of course, if f x and x.f mean the same thing, we don't need
x.f, do we?


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
1234
Loading...