[Haskell-cafe] I'm afraid of OverloadedLabels.

Nikita Churaev lamefun.x0r at gmail.com
Sun Jul 9 21:03:24 UTC 2017

> AND PLEASE not the way an [existing proposal] suggests to do
> it!  Please
> let's just do ad-hoc overloading.  There is no reason to introduce
> new
> syntax, because syntax is completely orthogonal to this problem.

I think that a new syntax is needed though. Here's my reasoning:

Why do mainstream OOP languages have it so easy, while Haskell hasn't
been able to solve the name collision problem for many, many years?

I think one of the obstacles is that currying has encouraged most
libraries to put any object arguments last, eg:

    insert :: Int -> a -> [a] -> [a]
    insert :: a -> Set a -> Set a
    insert :: k -> v -> Map k v -> Map k v

instead of putting it first (like in most OOP languages):

    insert :: [a] -> Int -> a -> [a]
    insert :: Set a -> a -> Set a
    insert :: Map k v -> k -> v -> Map k v

I think this is precisely the reason why OOP languages have it easy
while Haskell is struggling.

If the significant argument is predictably first, TNDR is super-easy to
implement even in current Haskell, if you are willing to create a class
for every single method:

    {-# LANGUAGE FunctionalDependencies #-}
    {-# LANGUAGE FlexibleInstances #-}

    import Data.Set (Set)
    import Data.Map (Map)
    import qualified Data.Set as Set
    import qualified Data.Map as Map

    class Insert a f | a -> f where
        insert :: a -> f

    instance Insert [a] (Int -> a -> [a]) where
        insert list at item = take at list ++ [item] ++ drop at list

    instance Ord a => Insert (Set a) (a -> Set a) where
        insert set item = Set.insert item set

    instance Ord k => Insert (Map k v) (k -> v -> Map k v) where
        insert map k v = Map.insert k v map

    main = do
        print (insert [1, 3, 4] 1 2)
        print (insert Set.empty "hello")
        print (insert Map.empty "hello" "world")

So, a new syntax is surely needed if the TNDR implementation relies on
object arguments being the first, since $ no longer works for such

Also, I think that methods should get a namespace of their own, just
like operators. The reason is to preserve backwards compatibility
without having to create any new modules: methods can be implemented
alongside old-style functions.

Another reason:

    let name = person.name in ...

If the .name method is in a namespace of its own, the name variable
doesn't become ambiguous (with all associated problems).

I don't think it would even be necessary to introduce any ambiguity-
resolving behaviour into normal namespace if methods are in a namespace
of their own.

Methods would be defined like this:

    .insert :: Ord k => Map k v -> k -> v -> Map k v
    .insert map k v = ...

Invoked like this (just like in existing proposal):

    Map.empty .insert "hello" "world"
              .insert "cat" "meow"
              .insert "haskell" "awesome"

Currying by not applying the object:

    .insert x y :: Map k v -> Map k v

Currying by not applying the arguments:

    map .insert :: k -> v -> Map k v

Prefix application:

    (.insert) map k v

More information about the Haskell-Cafe mailing list