2008-12-18 14 views
8

Provenendo da C++, trovo indispensabile la programmazione generica. Mi chiedo come si avvicinano le persone a Haskell?Come si fa la programmazione generica in Haskell?

Dire come si scrive la funzione di scambio generico in Haskell?

Esiste un concetto equivalente di specializzazione parziale in Haskell?

In C++, posso parzialmente specializzare la funzione di scambio generico con uno speciale per un contenitore generico map/hash_map che ha un metodo di scambio speciale per O (1) scambio di container. Come lo fai in Haskell o qual è l'esempio canonico di programmazione generica in Haskell?

+31

Questo è uno scherzo, giusto? È come chiedere come si possa avere un controllo preciso su tutto in assemblea: P – ShreevatsaR

+0

Niente a che vedere con il montaggio, davvero. Basta mantenere la stessa interfaccia con una famiglia di algoritmi. – obecalp

+3

A parte la strana domanda sulla programmazione generica e la specializzazione parziale (cercare curriculum), la domanda sullo "scambio di variabili" è anche strana: non esiste una cosa come "scambiare il contenuto di due caselle" in Haskell, perché le variabili in Haskell sono * non * scatole con dati in esse. – ShreevatsaR

risposta

27

Ciò è strettamente legato alla tua altra domanda circa Haskell e quicksort. Penso che probabilmente dovrai leggere almeno l'introduzione di un libro su Haskell. Sembra come se non avessi ancora afferrato il punto chiave su di esso che è che ti impedisce di modificare i valori delle variabili esistenti.

Swap (come compreso e utilizzato in C++) è, per sua stessa natura, tutto sulla modifica valori esistenti. È così che possiamo usare un nome per fare riferimento a un contenitore e sostituire quel contenitore con contenuti completamente diversi e specializzare quell'operazione per essere veloce (e senza eccezioni) per contenitori specifici, permettendoci di implementare un approccio di modifica e pubblicazione (fondamentale per scrivere codice eccezionalmente sicuro o tentare di scrivere codice senza blocco).

È possibile scrivere uno scambio generico in Haskell, ma probabilmente richiederebbe una coppia di valori e restituire una nuova coppia contenente gli stessi valori con le posizioni invertite, o qualcosa del genere. Non proprio la stessa cosa, e non avendo gli stessi usi. Non avrebbe alcun senso provare e specializzarlo per una mappa scavando all'interno di quella mappa e scambiando le sue variabili membro individuali, perché non ti è permesso fare cose del genere in Haskell (puoi fare la specializzazione, ma non la modifica delle variabili).

Supponiamo che volevamo "misura" una lista in Haskell:

measure :: [a] -> Integer 

Questa è una dichiarazione di tipo. Significa che la funzione measure prende un elenco di qualsiasi cosa (a è un parametro di tipo generico perché inizia con una lettera minuscola) e restituisce un numero intero. Quindi questo funziona per un elenco di qualsiasi tipo di elemento: è quello che verrebbe chiamato un modello di funzione in C++ o una funzione polimorfica in Haskell (non la stessa di una classe polimorfica in C++).

Possiamo ora definire che, fornendo specializzazioni per ogni caso interessante:

measure [] = 0 

cioè misurare la lista vuota e si ottiene zero.

Ecco una definizione molto generale che copre tutti gli altri casi:

measure (h:r) = 1 + measure r 

Il bit tra parentesi sul lato sinistro è un modello. Significa: prendere una lista, staccare la testa e chiamarla h, chiamare la parte restante r. Questi nomi sono quindi parametri che possiamo usare. Questo corrisponderà a qualsiasi elenco con almeno un elemento su di esso.

Se hai provato la metaprogrammazione del modello in C++, questo sarà tutto vecchio per te, perché implica esattamente lo stesso stile - ricorsione per fare cicli, specializzazione per far terminare la ricorsione. Tranne che in Haskell funziona in runtime (specializzazione della funzione per particolari valori o modelli di valori).

+0

è l'esempio canonico di C++ gp. Puoi provare ad illustrare lo stesso concetto con un esempio di Haskell canonico. Ho rivisto la domanda per riflettere questo. – obecalp

9

Come Earwicker sais, l'esempio non è così significativo in Haskell. Se si vuole assolutamente avere in ogni caso, qui è qualcosa di simile (scambiando le due parti di una coppia), c & p da una sessione interattiva:

GHCi, version 6.8.2: http://www.haskell.org/ghc/ :? for help 
Loading package base ... linking ... done. 
Prelude> let swap (a,b) = (b,a) 
Prelude> swap("hello", "world") 
("world","hello") 
Prelude> swap(1,2) 
(2,1) 
Prelude> swap("hello",2) 
(2,"hello") 
+4

Si prega di tenere presente che questo in realtà non scambia i valori ma restituisce una nuova coppia (poiché la coppia originale è immutabile). – TheMarko

+0

È molto simile a ciò che ocaml fa. Cosa succede se voglio scambiare due tabelle hash o una mappa, come garantite che i valori non vengano copiati? – obecalp

+0

Se si desidera operare su grandi tabelle di stato, probabilmente non si desidera utilizzare la programmazione funzionale in primo luogo. Se è assolutamente necessario, c'è IORef e la monade di stato per eseguire calcoli che mantengono uno stato. – TheMarko

2

Dopo aver letto abbastanza in un libro Haskell per capire veramente la risposta di Earwicker Ti suggerisco di leggere anche le lezioni di tipo. Non sono sicuro di cosa significhi "specializzazione parziale", ma sembra che potrebbero avvicinarsi.

6

In Haskell, le funzioni sono come generico (polimorfico) possibile - il compilatore dedurre il "tipo più generale". Ad esempio, ad esempio scambio di TheMarko è polimorfica di default in assenza di una firma tipo:

* principale> lasciare swap (a, b) = (b, a)
* principale>: t di swap
swap: : (t, t1) -> (t1, t)

quanto parziale specializzazione, ghc ha un'estensione non-98:
file:///C:/ghc/ghc-6.10.1/doc/users_guide/pragmas.html#specialize-pragma

si noti inoltre che c'è una mancata corrispondenza nella terminologia. Quello che viene chiamato generico in C++, Java e C# è chiamato polimorfico in Haskell. "Generico" in Haskell solito significa polytypic: http://haskell.readscheme.org/generic.html
Ma, aboe io uso il C++ significato di generico.

+1

Il tuo link è morto – Kos

+0

Grazie, entrambi sono morti, il primo non è nemmeno un link. Il primo dovrebbe essere: [link] http://lambda.haskell.org/platform/doc/current/ghc-doc/users_guide/pragmas.html#specialize-pragma e il secondo può essere trovato su archive.org: [collegamento] http://web.archive.org/web/20080511185727/http://haskell.readscheme.org/generic.html –

5

In Haskell è possibile creare classi di tipi. Le classi di tipi non sono come le classi nelle lingue OO. Prendi la classe di tipo Numeric. Dice che qualsiasi cosa che sia un'istanza della classe può eseguire determinate operazioni (+ - * /) in modo che Intero sia un membro di Numeric e offra implementazioni delle funzioni necessarie per essere considerato numerico e può essere utilizzato ovunque È previsto un numero.

dire che si desidera essere in grado di foo Ints e archi. Quindi dichiarerai Int e String come istanze della classe tipo Foo. Ora ovunque tu veda il tipo (Foo a) ora puoi usare Int o String.

Il motivo per cui non è possibile aggiungere direttamente e float è perché add ha il tipo (Numerico a) a -> a -> aa è una variabile di tipo e proprio come le variabili regolari può essere associato una sola volta così come non appena lo leghi ad Int ogni a nella lista deve essere Int.

Problemi correlati