I tipi vengono cancellati in Haskell?


13

Haskell ha una nozione di "funzioni generiche" che ha qualche apparente somiglianza con lisp comune - non avendo né esperienza con Haskell né con lisp comune, potrei essere molto approssimativo qui. Ciò significa che è possibile definire una to_stringstruttura generica per definire una rappresentazione di stringa per tutti i tipi. Naturalmente, la struttura deve essere definita in casi speciali, ma esiste una to_stringfunzione la cui firma è α → string.

I tipi vengono cancellati in Haskell, come lo sono in OCaml? In caso affermativo, in che modo l'implementazione di "funzioni generiche" in Haskell differisce da quella di lisp comune, dove i tipi sono dinamici e quindi non cancellati?

Comprendo che i dettagli di implementazione sono specifici del compilatore, ma probabilmente ci sono disposizioni comuni a molte o tutte le implementazioni.


5
Ricorda che probabilmente non puoi definire una funzione di tipo non banale a -> String. Probabilmente avresti un vincolo di tipo, come Show a => a -> String.
DJG

Risposte:


16

La risposta finora è fuorviante.

È necessario operare una distinzione tra polimorfismo "parametrico" e "sovraccarico ad hoc". Parametrico significa "si comporta in modo uniforme per tutti i tipi a", mentre "ad-hoc" - quello che Simon chiama polimorfico - cambia l'implementazione in base al tipo.

Esempi di entrambi sono reverse :: [a] -> [a], che è parametrico e show :: Show a => a -> Stringche è "ad hoc" sovraccarico.

Se vuoi più di un'intuizione astratta, penso che aiuti a considerare le classi di verbi del linguaggio naturale che "funzionano" per tutti gli oggetti, come "possedere" o "pensare" che non pongono vincoli sull'oggetto, ma " aprire "richiede che si possa aprire ciò di cui stiamo parlando. Posso "pensare a una porta" e "aprire una porta", mentre non ha senso, ad esempio, "aprire un albero". Per dare l'esempio ancora di più "aprire" è "polimorfico ad hoc" come "aprire una finestra" e "aprire un ticket di reclamo con il servizio clienti" sono due cose molto diverse. Se questo sembra forzato, dimenticalo! Per me funziona.

Entrambi vengono risolti in fase di compilazione, tuttavia, e in effetti "cancellati". Modulo estensioni varie GHC e Template Haskell, ecc Tipi sono infatti cancellati in fase di compilazione e non vengono mai controllati in fase di esecuzione.

Le funzioni parametricamente polimorfiche si comportano in modo identico per tutti i tipi, quindi è necessario generare solo un pezzo di codice, mentre il compilatore decide in fase di compilazione quale versione di una funzione "classificata per tipo" deve essere eseguita in un determinato punto del programma. Questo è anche il motivo per cui esiste la limitazione di un'istanza per tipo per classe di tipo e la soluzione "newtype" corrispondente.

L'implementazione è dettagliata nel libro di testo SPJ e nel documento di Wadler e Blotts sulle classi di tipo .


Pensi che dovrei eliminare la mia risposta?
Simon Bergot,

No, va bene con il tuo avvertimento di non toccare il vocabolario esatto:)
Kris

Potresti espandere un po 'il motivo per cui è possibile che GHC cancelli i tipi? È grazie alla digitazione principale?
Simon Bergot,

2
In generale in fase di runtime o le funzioni paramorficamente polimorfiche possono esistere una sola volta e chiamare le funzioni polimorfiche ad hoc tramite un metodo di invio virtuale oppure tutto il codice può essere generato separatamente per ciascun tipo e chiamate staticamente collegate. Entrambe le implementazioni sono corrette dal punto di vista del linguaggio (si noti che Haskell non ha tipi polimorfici; tale cosa può essere creata solo con l' forallestensione GHC ).
Jan Hudec,

Esistono estensioni GHC che non consentono la cancellazione dei tipi? Il sovraccarico è statico e senza tipi completamente dipendenti non riesco a pensare a nulla
Daniel Gratzer il

1

attenzione: il mio background in CS non è molto forte, quindi potrei non usare sempre il vocabolario corretto e potrei sbagliarmi su alcuni punti. Comunque, ecco la mia comprensione:

Penso che tu stia confondendo i generici con il polimorfismo.

Tipi generici come quelli List<Foo>utilizzati per descrivere tipi che accettano altri tipi come parametro e consentono un controllo del tipo più ricco.

Potrebbe essere una funzione generica in haskell count:: List a -> Int. Accetta elenchi di qualsiasi tipo e restituisce il numero di elementi. C'è solo una implementazione.

Di solito, quando si definisce Elenco, non si può assumere nulla su T. È possibile solo memorizzarlo e restituirlo.

Il tuo to_string funzione è una funzione polimorfica, il che significa che si comporterà in modo diverso in circostanze diverse. In haskell, questo viene fatto con le typeclass, che funzionano come aggettivi per i tipi.

Hai una Showtypeclass, che definisce una show :: a -> Stringfunzione.

Quando un tipo Fooimplementa la Showtypeclass, deve fornire la definizione di show. Questo tipo può quindi essere utilizzato nelle funzioni che richiedono il Showqualificatore (come in Show a => a -> whatever). Haskell non può cancellare i tipi, dal momento che tali funzioni devono trovare la corretta implementazione della showfunzione.


In lisp comune, le funzioni polimorfiche sono chiamate "funzioni generiche" IIRC e ho usato lo stesso vocabolario (confuso). La tua risposta è utile e il tuo argomento finale abbastanza convincente. .-)
user40989

"Esiste una sola implementazione", solo una che ha senso, certo, ma ce ne sono infinitamente possibili. Una funzione di tipo a → b ha | b | ^ | a | possibili implementazioni (considerare il numero di funzioni di tipo Bool → Bool) e gli elenchi non hanno limiti di dimensione superiore.
Jon Purdy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.