[Haskell-cafe] Type Directed Name Resolution

Gábor Lehel illissius at gmail.com
Thu Nov 11 04:33:14 EST 2010

I agree with the people who want to decouple the dot-syntax from TDNR
itself. To quote myself from the publicly-editable wiki page:

"This might be a really dumb question, but is there any reason TDNR
needs to be tied to a new syntax for function application? It seems
strange to me to have one syntax for left-to-right function
application without TDNR, and then another for right-to-left
application with it. I would much rather gain TDNR for the existing
syntax, and then maybe introduce the dot operator as a separate option
if people want it, which I don't. The reason I don't is that (.) as
composition and ($) already work in one direction, which is the same
direction (`foo . bar . baz $ bla` and `foo $ bar $ baz $ bla` are
interchangeable), and while in a vacuum I might even prefer the
opposite direction which (.)-as-application uses, it is much more
important to be consistent. We have a vast body of functions already
written and designed to be convenient with the existing direction:
functions are generally of the form `f :: (what to do) -> (what to do
it with) -> (result)`, which lends itself well to partial
application/currying and chaining in the existing direction, but not
the other one. (Object oriented languages which use the dot operator
indeed also use the reverse order for their methods, with the object
first and the action second.) Also, reading expressions where
different parts work in different directions is very confusing. The
one major exception which works in the other direction is monadic
bind, (>>=), which I think was a (minor) mistake, and indeed I
frequently end up using (=<<) instead. Anyway, executive summary: TDNR
yea, dot operator nay."

Some further thoughts.

I would have TDNR apply only in cases where:
- The functions are all imported from different modules (so you can't
define overlapping names within the same module);
- All of the functions have an explicit type signature;
- The ambiguity can be resolved by looking at the type of the first
(taking currying into account, only) parameter of each function and,
looking at the type constructors from the outside in, comparing only
type constructors which are concrete types, rather than type variables
(with or without constraints). E.g.:
-- f :: Int -> [...] and f :: Char -> [...] could be resolved;
-- f :: Foo Int -> [...] and f :: Foo Char -> [...] could be resolved;
-- f :: Foo a -> [...] and f :: Bar b -> [...] could be resolved;
-- f :: Num a => a -> [...] and f :: IsString b => b -> [...] could
*not* be resolved (even if it is known that the argument type doesn't
satisfy both constraints);
-- f :: a Int -> [...] and f :: b Char -> [...] could *not* be
resolved (though I'm less sure about this one).
-- Going by the above, neither Foo nor Bar can be type functions.
-- With more than two functions, each possible pair has to meet the conditions.

I don't have any well-articulated arguments to support this idea, yet;
it mainly just "feels right". My intuition for TDNR is that it has no
connection to semantics, and it is not intended as a means of defining
an interface: it is merely a syntactic convenience. If you want to
define an interface, use a type class. TDNR would be a convenience for
the case where you have imported multiple modules using a function of
the same name with obviously different types (whether the functions do
similar or different things is beside the point). Comparing to C++
(though it's unlikely to help my case to mention that language here,
but whatever), I feel that type classes : TDNR :: virtual functions :
static overloading.

And, in any case, as a language extension nobody would be forced to
use it if they don't like it. (I personally would find it very
useful). I think the fact that language extensions need to meet (much)
lesser criteria than changes to the language standard itself is
plainly evidenced by the existence of IncoherentInstances, which
nobody in their right mind would ever consider standardizing (or, for
that matter, ever enabling).

On Wed, Nov 10, 2010 at 10:59 AM, John Smith <voldermort at hotmail.com> wrote:
> Type-directed name resolution, as originally proposed for Haskell', has now
> been proposed for GHC. Obvious benefits of this are that conflicting
> function names from imported modules can be used without qualification
> (verbose) or pseudo-Hungarian renaming (verbose, and requires that you
> control the source, and perform the same renaming in all dependencies). This
> is important for both readability and programming in the large, particularly
> where records are concerned, as the duplicate name problem cannot be
> alleviated with typeclasses, and it is often desirable to have the same
> field names for many records in the same module.
> http://hackage.haskell.org/trac/ghc/ticket/4479
> http://hackage.haskell.org/trac/haskell-prime/wiki/TypeDirectedNameResolution
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe

Work is punishment for failing to procrastinate effectively.

More information about the Haskell-Cafe mailing list