2012-01-25 14 views
6

Sto lavorando al problema per scrivere codice Haskell simile a un programma C++.Implementare il sovraccarico della funzione in Haskell

Il codice C++ è:

class Rectangle 
{ 
    private: 
     int length; 
     int width; 
    public: 
     Rectangle() 
     { 
      length = 0; 
      width = 0; 
     } 
     Rectangle(int x) 
     { 
      length = x; 
      width =0; 
     } 
     Rectangle (int x , int y) 
     { 
      length = x; 
      width = y; 
     } 
}; 

Per scrivere simile codice Haskell ho fatto un tipo di dati rettangolo

data Rectangle = Rectangle Length Width deriving (Eq, Show , Read) 
type Length = Int 
type Width = Int 

Poi ho pensato di realizzare una funzione di carico che può agire come costruttore. Ma non capisco come implementare l'overloading di funzioni con un numero diverso di argomenti. Per favore aiuto. Grazie.

+1

Non mi preoccuperei di provare a modellare haskell dopo C++; porterà solo un sacco di dolore. Inoltre, perché il tuo secondo costruttore di rettangoli è una linea? Penso che un'implementazione più ragionevole sarebbe quella di default a (1, 1), e se ne ottieni una int, passa (x, x), per formare un quadrato. – alternative

+0

Hai mai sentito l'elenco di inizializzazione del costruttore? –

+2

@VladLazarenko: hai mai sentito parlare di persone che stanno ancora imparando? (Suggerimento: sei tra loro, tutti lo sono) –

risposta

21

Mentre è possibile fare tale sovraccarico in Haskell, non è considerato idiomatica, e sarà probabilmente portare a errori di confusione in seguito. Invece, si dovrebbe semplicemente definire le funzioni che costruiscono i dati:

point :: Rectangle 
point = Rectangle 0 0 

line :: Length -> Rectangle 
line l = Rectangle l 0 

square :: Int -> Rectangle 
square a = Rectangle a a 

Questo permette di dare nomi chiare che descrivono le semantica di ogni sovraccarico, piuttosto che basarsi su numero e sul tipo di argomenti dato a disambiguare cui si significare.

Tuttavia, se si vuole scrivere la versione di overload, lo si può fare facilmente con typeclasses:

class MakeRectangle a where 
    rectangle :: a 

instance MakeRectangle Rectangle where 
    rectangle = Rectangle 0 0 

instance MakeRectangle (Length -> Rectangle) where 
    rectangle l = Rectangle l 0 

instance MakeRectangle (Length -> Width -> Rectangle) where 
    rectangle = Rectangle 

Avrete bisogno {-# LANGUAGE FlexibleInstances #-} nella parte superiore del file per compilare questo. Un trucco come questo è usato dalla libreria standard Text.Printf, ma non lo considererei un esempio particolarmente valido di sovraccarico in Haskell; c'è quasi sempre una struttura per il tipo di valore sovraccarico, mentre qui la sua intera struttura è dettata dall'istanza, che può interferire con l'inferenza di tipo; non solo, ma non ci sono leggi ragionevoli che governano le istanze (anzi, il tipo è troppo generico per consentirne).

Ma se si vuole davvero farlo, è possibile, e anche se di solito è una cattiva idea, a volte (come nel caso di printf) è l'unico modo per realizzare l'interfaccia che si desidera.

di provare questo in GHCi, è necessario specificare i tipi che si sta utilizzando in modo esplicito, altrimenti non sarà in grado di risolvere i casi:

GHCi> rectangle :: Rectangle 
Rectangle 0 0 
GHCi> rectangle (1 :: Length) :: Rectangle 
Rectangle 1 0 
GHCi> rectangle (1 :: Length) (2 :: Width) :: Rectangle 
Rectangle 1 2 
+0

Non sono in grado di compilare il programma. L'errore è 'dichiarazioni multiple per il rettangolo' –

+0

Ti sei assicurato di conservare il rientro? Avete un'altra dichiarazione di 'rettangolo' altrove nel file? Se non è nessuno di questi, quindi aggiungi il file completo che stai compilando alla tua domanda e darò un'occhiata. – ehird

+1

Hai dimenticato di includere gli spazi dal mio codice; Haskell è un linguaggio sensibile all'indentazione. – ehird

22

È possibile utilizzare la sintassi del record per raggiungere tale comportamento.

data Rectangle = Rectangle {len :: Length, width :: Width} deriving (Eq, Show , Read) 
type Length = Int 
type Width = Int 

rectangle = Rectangle { len = 0, width = 0 } 

rectangle :: Rectangle sarà il tuo costruttore qui.

Ora è possibile definire alcune Rectangle valori:

λ> let a = rectangle {len = 1} 

λ> a 
Rectangle {len = 1, width = 0} 
4

non è quello che stai cercando semplicemente questo:

data Rectangle = Point | Line Int | Rectangle Int Int 
Problemi correlati