("Java", come usato qui, è definito come standard Java SE 7 ; "Haskell", come usato qui, è definito come standard Haskell 2010 .)
Cose che il sistema di tipi di Java ha ma che Haskell non ha:
- polimorfismo del sottotipo nominale
- informazioni sul tipo di runtime parziale
Cose che il sistema di tipi di Haskell ha ma che Java non ha:
- polimorfismo ad-hoc limitato
- dà origine al "polimorfismo di sottotipo" basato sui vincoli
- polimorfismo parametrico di tipo superiore
- tipizzazione principale
Modifica
Esempi di ciascuno dei punti sopra elencati:
Unico a Java (rispetto a Haskell)
Polimorfismo dei sottotipi nominali
/* declare explicit subtypes (limited multiple inheritance is allowed) */
abstract class MyList extends AbstractList<String> implements RandomAccess {
/* specify a type's additional initialization requirements */
public MyList(elem1: String) {
super() /* explicit call to a supertype's implementation */
this.add(elem1) /* might be overridden in a subtype of this type */
}
}
/* use a type as one of its supertypes (implicit upcasting) */
List<String> l = new ArrayList<>() /* some inference is available for generics */
Informazioni sul tipo di runtime parziale
/* find the outermost actual type of a value at runtime */
Class<?> c = l.getClass // will be 'java.util.ArrayList'
/* query the relationship between runtime and compile-time types */
Boolean b = l instanceOf MyList // will be 'false'
Unico per Haskell (rispetto a Java)
Polimorfismo ad-hoc limitato
-- declare a parametrized bound
class A t where
-- provide a function via this bound
tInt :: t Int
-- require other bounds within the functions provided by this bound
mtInt :: Monad m => m (t Int)
mtInt = return tInt -- define bound-provided functions via other bound-provided functions
-- fullfill a bound
instance A Maybe where
tInt = Just 5
mtInt = return Nothing -- override defaults
-- require exactly the bounds you need (ideally)
tString :: (Functor t, A t) => t String
tString = fmap show tInt -- use bounds that are implied by a concrete type (e.g., "Show Int")
Polimorfismo del sottotipo "basato sui vincoli" (basato sul polimorfismo ad-hoc limitato)
-- declare that a bound implies other bounds (introduce a subbound)
class (A t, Applicative t) => B t where -- bounds don't have to provide functions
-- use multiple bounds (intersection types in the context, union types in the full type)
mtString :: (Monad m, B t) => m (t String)
mtString = return mtInt -- use a bound that is implied by another bound (implicit upcasting)
optString :: Maybe String
optString = join mtString -- full types are contravariant in their contexts
Polimorfismo parametrico di tipo superiore
-- parametrize types over type variables that are themselves parametrized
data OneOrTwoTs t x = OneVariableT (t x) | TwoFixedTs (t Int) (t String)
-- bounds can be higher-kinded, too
class MonadStrip s where
-- use arbitrarily nested higher-kinded type variables
strip :: (Monad m, MonadTrans t) => s t m a -> t m a -> m a
Digitazione principale
Questo è difficile da dare un esempio diretto di, ma significa che ogni espressione ha esattamente un tipo massimale generale (chiamato il suo tipo principale ), che è considerato il tipo canonico di quell'espressione. In termini di polimorfismo del sottotipo "basato su vincoli" (vedi sopra), il tipo principale di un'espressione è il sottotipo unico di ogni tipo possibile che l'espressione può essere utilizzata come. La presenza del principale digitando in Haskell (non ampliato) è ciò che consente l'inferenza completa del tipo (vale a dire, l'inferenza di tipo riuscita per ogni espressione, senza bisogno di annotazioni di tipo). Le estensioni che interrompono la tipizzazione principale (di cui ce ne sono molte) interrompono anche la completezza dell'inferenza di tipo.