2010-03-05 20 views
8

Je veux redéfinir plusieurs opérateurs arithmétiques dans Haskell afin de les rendre plus extensibles et génériques.Haskell - Redéfinir (masquer) les opérateurs arithmétiques

E.g.

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

Cela semble fonctionner en combinaison avec

import Prelude hiding ((*)) 

cacher la norme opérateur *. Mais bien sûr, tous les multiplications habituelles doivent travailler, donc je dois définir quelque chose comme

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

Comment puis-je accéder à l'opérateur * d'origine (Prelude.(*) ne fonctionne pas) ici et comment dois-je définir le type d'instance de telle sorte que 1 * 1 ne soit pas en conflit avec le Monomorpism Restriction?


Modifier -

import qualified 

est un bon conseil, merci.

Mais malheureusement, cela m'a forcé à mettre explicitement toutes les méthodes standard dans la portée. Je veux juste avoir la possibilité de redéfinir certaines liaisons en laissant le reste inchangé.

Alors, y a-t-il une combinaison des deux? Quelque chose comme

import Prelude qualified ((*)) 

Répondre

23

Répondre à la question éditée:

Vous pouvez faire

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

pour avoir accès à toutes les fonctions Prélude à l'exception (*) de la manière habituelle et (*) via le préfixe P:

x = 5 + 3 -- works 
y = 5 P.* 3 -- works 
z = 5 * 3 -- complains about * not being in scope 
+1

Merci - C'est ce que je cherchais. – Dario

+0

Super! Vous êtes les bienvenus. –

3

Il y a eu quelques tentatives pour faire des choses comme ça.

Tout d'abord,

Comment puis-je accéder à l'opérateur original * (. Prelude (*) ne fonctionne pas)

Vous aurez besoin de:

import qualified Prelude 

maintenant vous pouvez utiliser par exemple (Prélude.*). Ceci est moins agressif que "LANGUAGE NoImplicitPrelude" qui provoquera également des utilisations locales de >> = et ainsi de suite à rebondir à vos définitions.

Voici des exemples de préludes alternatives d'autres personnes:

+0

Merci - Voir ma question éditée – Dario

2

Je peux répondre à la première question. Cacher l'opérateur (*) le cache vraiment, donc vous ne pouvez pas y arriver. Cependant, vous pouvez importer Prelude qualifié:

import qualified Prelude as P 

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

Je pense que cela fait ce que vous voulez.

4

L'instance

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

En grande partie vaincre le but d'avoir défini Mul t t t en premier lieu, sans abuser des extensions pour permettre {-# LANGUAGE OverlappingInstances #-}.

Malheureusement, le « droit » si la réponse douloureuse est de passer par exemple par exemple et faire

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) 
    ... 

Sinon, la façon dont les têtes d'instance seront résolus dans le compilateur (pas de retour arrière est fait) va probablement faire de votre roman les instances font sauter la compilation quand vous allez les utiliser.

Cela dit, vous pouvez au moins soulager la douleur pour les cas vous ne pensez:

newtype Other a = Other a 

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

Cela au moins les laisser utiliser simplement votre emballage newtype si elles ne veulent pas aller définissez Mul et toutes vos autres classes elles-mêmes.

+0

+1 Merci pour l'info – Dario