2011-12-16 9 views
8

ancora nuovo per Haskell, ho colpito un muro con il seguente:Tipo definizione di classe con le funzioni a seconda di un ulteriore tipo

sto cercando di definire alcune classi di tipo generalizzare un gruppo di funzioni che utilizzano l'eliminazione gaussiana per risolvere sistemi lineari di equazioni.

Dato un sistema lineare

M x = k 

tipo a degli elementi m(i,j) \elem M può essere diverso dal tipo di bx e k. Per poter risolvere il sistema, a dovrebbe essere un'istanza di Num e b dovrebbe avere operatori moltiplicazione/addizione con b, come nel seguente:

class MixedRing b where 
    (.+.) :: b -> b -> b 
    (.*.) :: (Num a) => b -> a -> b 
    (./.) :: (Num a) => b -> a -> b 

Ora, anche nella realizzazione più banale di questi operatori, prendo Could not deduce a ~ Int. a is a rigid type variable errori (Lasciamo perdere ./. che richiede Fractional)

data Wrap = W { get :: Int } 
instance MixedRing Wrap where 
    (.+.) w1 w2 = W $ (get w1) + (get w2) 
    (.*.) w s = W $ ((get w) * s) 

ho letto diversi tutorial su classi di tipo ma non riesco a trovare nessun puntatore a ciò che accade effettivamente sbagliato.

+5

C'è già un pacchetto che definisce questa classe: http://hackage.haskell.org/packages/archive/vector-space/0.8.0/doc/html/Data-VectorSpace.html Puoi dare un'occhiata qui. –

+0

@SjoerdVisscher: Grazie! – bbtrb

risposta

10

Diamo un'occhiata al tipo di implementazione che dovresti fornire per (.*.) per rendere Wrap un'istanza di MixedRing.Sostituendo Wrap per b nel tipo del metodo produce

(.*.) :: Num a => Wrap -> a -> Wrap 

Come Wrap è isomorfo a Int e di non dover pensare a confezionamento e l'apertura con Wrap e get, cerchiamo di ridurre il nostro obiettivo di trovare un'implementazione di

(.*.) :: Num a => Int -> a -> Int 

(si vede che questo non rende la sfida più facile o più difficile, non è vero?)

Ora, osserva che tale implementazione dovrà essere in grado di operare su tutti i tipi a che si trovano nella classe di tipo Num. (Questo è ciò che una variabile di tipo in tale tipo denota: quantificazione universale.) Nota: non è lo stesso (in realtà è l'opposto) di dire che la tua implementazione può scegliere da sola ciò che funziona su a); eppure questo è quello che sembra suggerire nella tua domanda: che la tua implementazione dovrebbe essere autorizzata a scegliere Int come scelta per a.

Ora, come si desidera implementare questa particolare (.*.) in termini di (*) per valori di tipo Int, abbiamo bisogno di qualcosa di forma

n .*. s = n * f s 

con

f :: Num a => a -> Int 

non riesco a pensare di una funzione che converte da un arborario Num -tipo a a Int in modo significativo. Direi quindi che non esiste un modo significativo per rendere Int (e, quindi, Wrap) un'istanza di MixedRing; cioè, non è tale che l'istanza si comporta come probabilmente ti aspetteresti che faccia.

+0

Ottima spiegazione. In realtà ci sono 2 errori: in primo luogo, non è possibile creare un'istanza a (dalla definizione della classe) nella definizione dell'istanza eb) alla via. *. è implementato causa b = a comunque e contraddice quindi il tipo di. *. dato in classe. – Ingo

+0

Grazie per questa eccellente spiegazione. Insieme alle altre risposte e al link al pacchetto 'VectorSpace' questo chiarisce il problema. – bbtrb

2

L'implementazione non è sufficientemente polimorfica.

La regola è, se si scrive a nella definizione della classe, non è possibile utilizzare un tipo concreto nell'istanza. Perché l'istanza deve essere conforme alla classe e la classe ha promesso di accettare qualsiasi a ovvero Num.

Per dirlo in modo diverso: esattamente la variabile di classe è quella che deve essere istanziata con un tipo concreto in una definizione di istanza.

Hai provato:

data Wrap a = W { get :: a } 

Nota che una volta Wrap a è un'istanza, è comunque possibile utilizzare con le funzioni che solo Wrap Int accettano.

+0

Sì, ho provato questo - con e senza l'istanza 'restric (Num a) => MixedRing (Wrap a) where' - e non ha aiutato. – bbtrb

+0

Ma a causa dell'implementazione di. *., Vedi il commento 'dblhelix'. – Ingo

6

ne dite qualcosa di simile:

class (Num a) => MixedRing a b where 
    (.+.) :: b -> b -> b 
    (.*.) :: b -> a -> b 
    (./.) :: b -> a -> b 

avrete bisogno l'estensione MultiParamTypeClasses.

A proposito, mi sembra che la struttura matematica che stai cercando di modellare sia in realtà modulo, non un anello. Con le variabili di tipo indicate in precedenza, si dice che b è un a -modulo.

+0

Non sapevo che ci sono classi di tipo multi parametro, questo funziona. E hai ragione, ovviamente, il modulo è il termine corretto. Fisico, non matematico qui, un'approssimazione è abbastanza buona;) – bbtrb

Problemi correlati