2010-03-05 18 views
8

Desidero ridefinire diversi operatori aritmetici in Haskell per renderli più estensibili e generici.Haskell - Ridefinizione (occultamento) degli operatori aritmetici

E.g.

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

Questo sembra funzionare in combinazione con

import Prelude hiding ((*)) 

nascondendo la * operatore standard. Ma, naturalmente, tutte le moltiplicazioni soliti lavorare così, quindi mi piacerebbe avere definire qualcosa come

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

Come posso accedere alla * dell'operatore originale (Prelude.(*) non funziona) qui e come devo definire il tipo di istanza in modo che 1 * 1 non sia in conflitto con la Limitazione di monomorfismo ?


Modifica -

import qualified 

è un buon suggerimento, grazie.

Ma sfortunatamente questo mi ha costretto a portare esplicitamente nello tutti i metodi standard. Voglio solo avere la possibilità di ridefinire determinati vincoli lasciando il resto invariato.

Quindi c'è una combinazione di entrambi? Qualcosa come

import Prelude qualified ((*)) 

risposta

23

Rispondendo alla domanda modificato:

Si può fare

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

per accedere a tutte le funzioni di Prelude, tranne (*) nel solito modo e per (*) tramite il P prefisso:

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

Grazie - Questo è quello che stavo cercando. – Dario

+0

Ottimo! Prego. –

3

Ci sono stati alcuni tentativi di fare cose come questa.

In primo luogo,

Come posso accedere dell'operatore originale * (. Prelude (*) non funziona)

avrete bisogno di:

import qualified Prelude 

ora puoi usare ad es (Preludio.*). Questo è meno aggressivo di "LANGUAGE NoImplicitPrelude" che causerà anche l'uso locale di >> = e così via per essere rimbalzato alle tue definizioni.

Ecco alcuni esempi di preludi alternativi di altre persone:

+0

Grazie - Vedere la mia domanda modificata – Dario

2

Posso rispondere alla prima domanda. Nascondere l'operatore (*) lo nasconde davvero, quindi non puoi farcela. Tuttavia, è possibile importare Prelude qualificato:

import qualified Prelude as P 

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

Penso che questo faccia quello che vuoi.

4

L'istanza

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

In gran parte vanificare lo scopo di aver definito Mul t t t in primo luogo, senza abusare delle estensioni per consentire {-# LANGUAGE OverlappingInstances #-}.

Purtroppo il 'diritto' se la risposta dolorosa è quella di passare attraverso caso per caso e fare

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

In caso contrario, il modo in cui le teste di istanza si risolvono nel compilatore (senza backtracking è fatto) sarà probabilmente renderà il vostro romanzo le istanze fanno esplodere la compilazione quando si usa effettivamente.

Detto questo, si può almeno alleviare il dolore per le istanze non hai pensato di:

newtype Other a = Other a 

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

Questo almeno far loro basta usare il tuo involucro Newtype, se non vogliono andare e definire Mul e tutte le altre classi stesse.

+0

+1 Grazie per le informazioni – Dario

Problemi correlati