Perché Haskell non è in grado di evitare ripetute valutazioni senza la limitazione del monomorfismo?


14

Ho appena finito learnyouahaskell l'altro giorno e stavo cercando di dare un senso alla restrizione del monomorfismo, come descritto dal Wiki di Haskell . Penso di capire come l'MR può impedire valutazioni ripetute, ma non riesco a capire perché tali valutazioni ripetute non possano essere evitate con mezzi molto più semplici.

L'esempio specifico che ho in mente è quello usato dal wiki:

f xs = (len,len)
  where
    len = genericLength xs

dov'è genericLengthdi tipo Num a => [b] -> a.

Ovviamente, genericLength xsdeve essere calcolato una sola volta per valutare (len,len), poiché è la stessa funzione con gli stessi argomenti. E non abbiamo bisogno di vedere invocazioni fper saperlo. Quindi perché Haskell non può fare questa ottimizzazione senza introdurre una regola come la MR?

La discussione su quella pagina wiki mi dice che ha qualcosa a che fare con il fatto che Numè una typeclass piuttosto che un tipo concreto, ma anche così, non dovrebbe essere ovvio in fase di compilazione che una funzione pura restituirebbe lo stesso valore- -e quindi lo stesso tipo concreto di Num - quando vengono dati gli stessi argomenti due volte?

Risposte:


11

È lo stesso nome di funzione, con gli stessi argomenti, ma tipi di ritorno e implementazioni potenzialmente diversi, perché è polimorfico. Ciò significa che se viene chiamato in un contesto in attesa di un (Int, MyWeirdCustomNumType)tipo restituito, deve valutarlo due volte, poiché l'implementazione di (+)in Intè completamente diversa dall'implementazione di (+)in MyWeirdCustomNumType. È necessario eseguire codice fisicamente diverso a un certo punto.

Ecco perché è importante che Numsia una classe di tipo. Significa che hai implementazioni diverse per tipi diversi. Significa anche che se si ftrova in una libreria, al momento della compilazione non conosce tutte le combinazioni di tipi che potrebbe essere necessario restituire.

Quindi, sì, devi vedere le invocazioni fper sapere quali tipi di restituzione usare. La maggior parte delle volte, ti aspetteresti che siano uguali, motivo per cui mettono di default la restrizione al monomorfismo. Può essere disattivato per quelle rare occasioni in cui non lo fai. In pratica, i programmatori non tendono a lasciare questo tipo di situazioni fino a digitare l'inferenza comunque.


Non avevo considerato la possibilità di f [] :: (Int, Float). Ora ha perfettamente senso. Grazie.
Ixrec,

1
It's the same function name, with the same arguments, but potentially different return types and implementations, because it's polymorphic.Penso che il modo migliore di vederlo sia che l'istanza della typeclass sia effettivamente un argomento in più genericLengthe il compilatore non è convinto che sia lo stesso argomento in entrambe le chiamate.
Doval,

Domanda a margine rapida. Se MonomorphismRestriction è disattivato, ma in seguito hai fatto qualcosa del genere a = uncurry (==) $ f [1, 2, 3]Sarebbe in grado di ottimizzare quel sito di chiamata per controllare la durata di [1, 2, 3]una sola volta? Se è così, allora sono davvero confuso su ciò che la restrizione del monomorfismo ti sta effettivamente acquistando, se no, allora perché no?
punto
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.