Crazy idea: overloading function application notation

This is a crazy idea I've been working on: overload the syntax "x y" so it can mean function application "f x = f(x)" or multiplication "x y = x*y". The reason is simply that I appreciate the brevity of MLs function application but I also appreciate the brevity of Mathematica's multiplication. Is it possible to implement this in Haskell using type classes? Is there any way this could actually be practicable? -- Dr Jon D Harrop, Flying Frog Consultancy Ltd. OCaml for Scientists http://www.ffconsultancy.com/products/ocaml_for_scientists/?e

Jon,
This is a crazy idea I've been working on: overload the syntax "x y" so it can mean function application "f x = f(x)" or multiplication "x y = x*y". The reason is simply that I appreciate the brevity of MLs function application but I also appreciate the brevity of Mathematica's multiplication.
Is it possible to implement this in Haskell using type classes? Is there any way this could actually be practicable?
Well, of course, it is certainly not possible to implement it directly. Juxtaposition denotes by no means an ordinary binary operator. If you do pick an ordinary binary operator for application, say (#), then you can get quite far with some language extensions, although I think it'll render your code less readable. Anyway, I remember doing this dark deed once when working with finite maps. I use associated type synonyms here, because we should get used to them anyway ;-). However, I'll attach a snippet employing functional dependencies, so you can actually play with it: infixl 9 # class Fun a where type Dom a :: * type Cod a :: * (#) :: a -> Dom a -> Cod a Now, let's have some fun ;-). instance Fun (a -> b) where type Arg (a -> b) = a type Res (a -> b) = b (#) = ($) instance Fun Int where type Arg Int = Int type Res Int = Int (#) = (*) instance Fun Bool where type Arg Bool = Bool type Res Bool = Bool (#) = (&&) instance (Eq a) => Fun [(a, b)] where type Arg [(a, b)] = a type Res [(a, b)] = Maybe b (#) = flip lookup And here we go: head # [2, 3, 5] ==> 2 2 # 3 ==> 6 False # True ==> False [('E', 2), ('H', 3), ('C', 5)] # 'E' ==> Just 2 Now, how practicable is it? As said, I think constructions like this have a negative impact on the readability of your programs. Moreover, overloading function applications is bound to introduce a lot of ambiguities in your programs and, hence, the need for type annotations. Cheers, Stefan

Jon,
This is a crazy idea I've been working on: overload the syntax "x y" so it can mean function application "f x = f(x)" or multiplication "x y = x*y".
On a related (?) note, but definitely not what you're after: there are constructor classes that allow you to lift function application into a functor and equip it with specific semantics: fmap :: (Functor f) => (a -> b) -> f a -> f b (<*>) :: (Applicative f) => f (a -> b) -> f a -> f b (=<<) :: (Monad m) => (a -> m b) -> m a -> m b Cheers, Stefan

This is a crazy idea I've been working on: overload the syntax "x y" so it can mean function application "f x = f(x)" or multiplication "x y = x*y". The reason is simply that I appreciate the brevity of MLs function application but I also appreciate the brevity of Mathematica's multiplication.
Is it possible to implement this in Haskell using type classes? Is there any way this could actually be practicable?
i'm not sure about practicalities - since Haskell programs are mostly identifiers and their applications, redefining application is going to lead to confusion. general rule for extending pure functional languages: do not mess with application, or you risk losing your nice theory. a rather steep price to pay for replacing '*' with ' ', no? you could, however, define a 'Num' instance for functions so that 'f * g = f . g' and 'fromInteger n = fromInteger . const n' or similar (though the types are not likely to make you happy), or you could try replacing the standard 'Num' class with one permitting differently- typed parameters to '(*)', and then try to define multiplication as application rather than composition.. (and if you think that is confusing, think again about overloading application;-) the rest of this message will not help with your particular problem, but is in reply to your subject line: in general, Haskeller's like to enjoy the advantages of overloading something so fundamental as application without endangering that fundament, even if that means a little more typing to indicate where a non-standard overloading is possible. so overloaded application uses a different notation and conventions. recall that '($)' is function application, and consider the following types: flip ($) :: a -> (a -> b) -> b (>>=) :: (Monad m) => m a -> (a -> m b) -> m b you'll notice that monadic bind corresponds to reverse function application, lifted into a monad. of course, there are many ways to do such lifting, so it is interesting to consider what the particular choice of monadification here means. if we permit monadic effects in all of parameter, function, and result, we'd get a type like this for lifted, reversed function application: m a -> m (m a -> m b) -> m b the type of '(>>=)' differs from this in two positions, meaning no monadic effects while computing the function, and no monadic effects in the function parameter _after_ substitution into the function body. the latter implies that, even though Haskell's standard application is based on call-by-need (or call-by-name, since sharing isn't required), its monadic application is based on call-by-value: any monadic effects in computing the argument have to be executed _before_ passing the (effect-free part of the) argument to the function. i've often wondered about this discrepancy. but if you just want overloaded application, rather than mess with the meaning and notation of built-in application, Monads may be the way to go. it might also give one indication of why Monads are so popular in Haskell, and so little heard of in languages which do allow unconstrained overloading of application. claus

Claus Reinke wrote:
This is a crazy idea I've been working on: overload the syntax "x y" so it can mean function application "f x = f(x)" or multiplication "x y = x*y". The reason is simply that I appreciate the brevity of MLs function application but I also appreciate the brevity of Mathematica's multiplication.
Is it possible to implement this in Haskell using type classes? Is there any way this could actually be practicable?
i'm not sure about practicalities - since Haskell programs are mostly identifiers and their applications, redefining application is going to lead to confusion. general rule for extending pure functional languages: do not mess with application, or you risk losing your nice theory. a rather steep price to pay for replacing '*' with ' ', no?
you could, however, define a 'Num' instance for functions so that 'f * g = f . g' and 'fromInteger n = fromInteger . const n' or similar (though the types are not likely to make you happy), or you could try replacing the standard 'Num' class with one permitting differently- typed parameters to '(*)', and then try to define multiplication as application rather than composition.. (and if you think that is confusing, think again about overloading application;-)
Indeed. This change would -definitely- lead to massive ambiguity and potentially lead to unresolvable cases.
the rest of this message will not help with your particular problem, but is in reply to your subject line: in general, Haskeller's like to enjoy the advantages of overloading something so fundamental as application without endangering that fundament, even if that means a little more typing to indicate where a non-standard overloading is possible. so overloaded application uses a different notation and conventions. recall that '($)' is function application, and consider the following types:
flip ($) :: a -> (a -> b) -> b (>>=) :: (Monad m) => m a -> (a -> m b) -> m b
you'll notice that monadic bind corresponds to reverse function application, lifted into a monad. of course, there are many ways to do such lifting, so it is interesting to consider what the particular choice of monadification here means.
if we permit monadic effects in all of parameter, function, and result, we'd get a type like this for lifted, reversed function application:
m a -> m (m a -> m b) -> m b
the type of '(>>=)' differs from this in two positions, meaning no monadic effects while computing the function, and no monadic effects in the function parameter _after_ substitution into the function body. the latter implies that, even though Haskell's standard application is based on call-by-need (or call-by-name, since sharing isn't required), its monadic application is based on call-by-value: any monadic effects in computing the argument have to be executed _before_ passing the (effect-free part of the) argument to the function.
i've often wondered about this discrepancy.
Laziness "causes" Haskell to be pure because understanding side-effecting code in a lazy language is... tricky to say the least. Why then would we want laziness for monads? Also, nothing is stopping you from defining a "lazy" apply when you -do- want it.
but if you just want overloaded application, rather than mess with the meaning and notation of built-in application, Monads may be the way to go. it might also give one indication of why Monads are so popular in Haskell, and so little heard of in languages which do allow unconstrained overloading of application.
Um... they are probably so little heard of in languages that allow unconstrained overloading of application because they are so little heard of in -any- other language.

Derek Elkins after a long chain which began:
This is a crazy idea I've been working on: overload the syntax "x y" so it can mean function application "f x = f(x)" or multiplication "x y = x*y".
... This change would -definitely- lead to massive ambiguity and potentially lead to unresolvable cases.
My favourite example of a guaranteed mess is the implementation of Peano- Church numerals as polymorphic functions in Haskell. You can multiply them, you can act with one upon another one as well. But the multiplication is the composition, and the functional application is the (inverted) exponentiation! I belive that trying to produce something similar to the proposal above would result in a True Disgrace. Jerzy Karczmarczuk

On 31/05/07, Jon Harrop
Is it possible to implement this in Haskell using type classes? Is there any way this could actually be practicable?
I had a go but didn't manage to quite get it. Here's my attempt, and the error it produces: {-# OPTIONS_GHC -fglasgow-exts #-} type Endo a = a -> a -- Dummy instances to satisfy the (Show n, Eq n) => Num n constraints instance Show (Endo a) where show _ = "<function>" instance Eq (Endo a) where _ == _ = False instance Num a => Num (Endo a) where fromInteger x = (fromInteger x *) x + y = \z -> x z + y z x * y = \z -> x z * y z abs x = error "Aaargh." signum x = error "Aaargh." main = print (2 3) /home/david/hs/sandbox/application-multiplication.hs:15:14: No instance for (Num (t -> a)) arising from the literal `2' at /home/david/hs/sandbox/application-multiplication.hs:15:14-16 Possible fix: add an instance declaration for (Num (t -> a)) In the first argument of `print', namely `(2 3)' In the expression: print (2 3) In the definition of `main': main = print (2 3) Failed, modules loaded: none. It seems to be wanting a more general instance than the one I'm providing, for whatever reason. Using print ((2 :: Endo Integer) 3) works, but that's hardly satisfactory. -- -David House, dmhouse@gmail.com

On Thu, 31 May 2007, Jon Harrop wrote:
This is a crazy idea I've been working on: overload the syntax "x y" so it can mean function application "f x = f(x)" or multiplication "x y = x*y". The reason is simply that I appreciate the brevity of MLs function application but I also appreciate the brevity of Mathematica's multiplication.
Is it possible to implement this in Haskell using type classes?
Is this "wantable"?
Is there any way this could actually be practicable?
On http://www.haskell.org/haskellwiki/Num_instance_for_functions I have described, what happens if you want too many meanings for the same syntax.
participants (7)
-
Claus Reinke
-
David House
-
Derek Elkins
-
Henning Thielemann
-
jerzy.karczmarczuk@info.unicaen.fr
-
Jon Harrop
-
Stefan Holdermans