La parametrricità riguarda i valori dei tipi con variabili. T
non ha variabili, quindi la parametrica non si applica. Infatti, T ha molti abitanti
ap :: T -> T -> T
ap (MkT f) t = f t
idT :: T
idT = MkT id
constT :: T
constT = MkT $ \t -> MkT $ \_ -> t
axiom_sT :: T
axiom_sT = MkT $ \f -> MkT $ \g -> MkT $ \a -> (g `ap` a) `ap` (f `ap` a)
Il tipo T
è un'implementazione del Untyped Lambda Calculus, un sistema universale equivalente formale di alimentazione ad una macchina di Turing. Le tre funzioni sopra (più ap
) formano il calcolo dello SKI, un sistema formale equivalente.
È possibile codificare qualsiasi tipo di dati Haskell in T
. Si consideri il tipo per numeri naturali
data Nat = Zero | Succ Nat
possiamo codificare Nat
in T
church :: Nat -> T
church Zero = MkT $ \f -> MkT $ \x -> x
church (Succ n) = MkT $ \f -> MkT $ \x -> f `ap` (church n)
ora, si è parzialmente corretto però. In Haskell non c'è modo di scrivere la funzione inversa di questo (per quanto ne so). Il che è davvero un peccato. Sebbene sia possibile scrivere una sorta di psuedo inverso con il tipo T -> IO Nat
. Inoltre, la mia comprensione è che l'ottimizzatore di GHC può morire su newtypes
ricorsivo (qualcuno mi corregga se ho torto su questo, perché mi piacerebbe tornare a usarli).
Invece, il tipo
data T = MkT (T -> T) | Failed String
con
ap (MkT f) a = f a
ap (Failed s) _ = Failed s
che è lambda calcolo con eccezioni, può essere utilizzato in modo completamente invertibile.
In conclusione, in un certo senso T
non è affatto un tipo utile, ma in un altro senso è il tipo più utile di tutti.
fonte
2012-12-04 04:00:59
Grazie per aver chiarito la mia confusione. –
Sfortunatamente non hai torto - almeno, l'inliner di GHC 7.6 può andare in panico su alcune espressioni che coinvolgono tipi con ricorsione negativa (questo può accadere con 'data' e' newtype'). La ricorsione positiva - cioè sul lato destro di '->' - dovrebbe andare bene, comunque. – shachaf