Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell - Redefining (hiding) arithmetic operators

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 ((*))
like image 597
Dario Avatar asked Mar 05 '10 17:03

Dario


People also ask

What does ++ do Haskell?

The ++ operator is the list concatenation operator which takes two lists as operands and "combines" them into a single list.

What does -> mean in Haskell?

(->) is often called the "function arrow" or "function type constructor", and while it does have some special syntax, there's not that much special about it. It's essentially an infix type operator. Give it two types, and it gives you the type of functions between those types.

What does in do in Haskell?

in goes along with let to name one or more local expressions in a pure function.

What is operators in Haskell?

Haskell provides special syntax to support infix notation. An operator is a function that can be applied using infix syntax (Section 3.4), or partially applied using a section (Section 3.5).


4 Answers

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
like image 112
Michał Marczyk Avatar answered Oct 13 '22 18:10

Michał Marczyk


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.

like image 34
Edward Kmett Avatar answered Oct 13 '22 19:10

Edward Kmett


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:

  • http://hackage.haskell.org/package/prelude-plus -- a simpler prelude (?)
  • http://hackage.haskell.org/package/numeric-prelude -- an alternative numerical hierarchy.
like image 3
Don Stewart Avatar answered Oct 13 '22 18:10

Don Stewart


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.

like image 2
tredontho Avatar answered Oct 13 '22 19:10

tredontho