Mi chiedo se ci siano modi generali per convertire tra le funzioni polimorfiche ad-hoc e quelle polimorfiche parametriche. In altre parole, data una funzione polimorfica ad-hoc, come implementare la sua controparte parametrica? e il contrario?buon modo per convertire tra le funzioni polimorfiche ad-hoc e quelle polimorfiche parametriche
prendere sort
come un esempio. è facile scrivere sort :: Ord a => [a] -> [a]
in termini di sortBy
:
sort :: Ord a => [a] -> [a]
sort = sortBy compare
ma il contrario sembra difficile, finora il migliore che posso fare è di andare un po ' "object-oriented":
import qualified Data.List as L
data OrdVal a = OV (a -> a -> Ordering) a
instance Eq (OrdVal a) where
(OV cmp a) == (OV _ b) = a `cmp` b == EQ
instance Ord (OrdVal a) where
(OV cmp a) `compare` (OV _ b) = a `cmp` b
sortBy :: (a -> a -> Ordering) -> [a] -> [a]
sortBy cmp = map unOV . L.sort . map (OV cmp)
where
unOV (OV _ v) = v
Ma questo suona più come un hack che una soluzione adeguata.
quindi mi piacerebbe sapere:
- ci sono modi migliori per questo esempio specifico?
- Quali sono le tecniche generali per la conversione tra funzioni polimorfiche ad-hoc e quelle parametriche?
Se potessimo passare dizionari (ad esempio impliciti in Agda), questo sarebbe banale. Tuttavia, credo che alcune classi/librerie sfruttino il fatto che non possiamo passare i dizionari per garantire alcuni invarianti. Ad esempio, immagina di poter chiamare "DataSet.insert" usando un diverso ordine ogni volta ... – chi
Nota anche che il tuo "hack" funziona in pratica, ma solo se non impacchetti due distinte funzioni 'cmp' in' OrdVal a' valori. Se lo fai, allora l'istanza di 'Ord' non soddisfa le leggi di' Ord'. – chi