views:

281

answers:

4

I want to redefine several arithmetic operators in Haskell in order to make them more extensible and generic.

E.g.

class Mul a b c | a b -> c where
    (*) :: a -> b -> c

This seems to work in combination with

import Prelude hiding ((*))

hiding the standard * operator. But of course all usual multiplications have to work as well, so I'd have to define something like

instance (Num t) => Mul t t t where
    (*) = ??

How can I access the original * operator (Prelude.(*) doesn't work) here and how do I have to define the instance type such that 1 * 1 doesn't conflict with the Monomorpism Restriction?


Edit -

import qualified

is a good tip, thanks.

But unfortunately this forced me to bring all standard methods into scope explicitly. I just want to have the possibility of redefining certain bindings leaving the rest unchanged.

So is there a combination of both? Something like

import Prelude qualified ((*))
+2  A: 

There have been a few attempts to do things like this.

Firstly,

How can I access the original * operator (Prelude.(*) doesn't work)

You'll need to:

import qualified Prelude 

now you can use e.g. (Prelude.*). This is less aggressive than "LANGUAGE NoImplicitPrelude" which will also cause local uses of >>= and so on to be rebound to your definitions.

Here are examples of other people's alternative preludes:

Don Stewart
Thanks - See my edited question
Dario
+1  A: 

I can answer the first question. Hiding the (*) operator really hides it, so you can't get at it. However, you can import Prelude qualified:

import qualified Prelude as P

foo = 3 P.* 14 -- == 42

I think that that does what you want.

tredontho
+12  A: 

Answering the edited question:

You can do

import Prelude hiding ((*))
import qualified Prelude as P

to gain access to all Prelude functions except (*) in the usual way and to (*) via the P prefix:

x = 5 + 3   -- works
y = 5 P.* 3 -- works
z = 5 * 3   -- complains about * not being in scope
Michał Marczyk
Thank you - That's what I was looking for.
Dario
Great! You're welcome.
Michał Marczyk
+3  A: 

The instance

instance (Num t) => Mul t t t where
    (*) = ??

Will largely defeat the purpose of having defined Mul t t t in the first place, without abusing extensions to allow {-# LANGUAGE OverlappingInstances #-}.

Unfortunately the 'right' if painful answer is to go through instance by instance and do

import Prelude hiding ((*))
import qualified Prelude 

instance Mul Int Int Int where
    (*) = (Prelude.*)

instance Mul Double Double Double where
    (*) = (Prelude.*)


instance Mul Int Double Double where
    ...

instance Mul (Complex Float) (Complex Double) (Complex Double)
    ...

Otherwise the way that instance heads get resolved in the compiler (no backtracking is done) will probably make your novel instances cause compilation to blow up when you go to actually use them.

That said, you can at least ease the pain for instances you didn't think of:

newtype Other a = Other a

instance Num a => Mul (Other a) (Other a) (Other a) where
    Other a * Other b = Other (a Prelude.* b)

This will at least let them just use your newtype wrapper if they don't want to go and define Mul and all of your other classes themselves.

Edward Kmett
+1 Thanks for the info
Dario