("Java", conforme usado aqui, é definido como padrão Java SE 7 ; "Haskell", conforme usado aqui, é definido como padrão Haskell 2010. )
Coisas que o sistema de tipos de Java tem, mas o de Haskell não:
- polimorfismo do subtipo nominal
- informações do tipo de tempo de execução parcial
Coisas que o sistema de tipos de Haskell tem, mas o Java não:
- polimorfismo ad-hoc limitado
- gera polimorfismo de subtipo "baseado em restrições"
- polimorfismo paramétrico de tipo superior
- digitação principal
EDITAR:
Exemplos de cada um dos pontos listados acima:
Exclusivo para Java (em comparação com Haskell)
Polimorfismo do subtipo nominal
/* 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 */
Informações do tipo de tempo de execução parcial
/* 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'
Exclusivo para Haskell (em comparação com Java)
Polimorfismo ad-hoc limitado
-- 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 de subtipo "baseado em restrições" (baseado em polimorfismo ad-hoc limitado)
-- 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 paramétrico de tipo superior
-- 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
Digitação principal
É difícil dar um exemplo direto disso, mas significa que toda expressão tem exatamente um tipo maximamente geral (chamado de tipo principal ), que é considerado o tipo canônico dessa expressão. Em termos de polimorfismo de subtipo "baseado em restrição" (veja acima), o tipo principal de uma expressão é o subtipo exclusivo de todos os tipos possíveis com os quais essa expressão pode ser usada. A presença da digitação principal em Haskell (sem extensão) é o que permite inferência de tipo completa (ou seja, inferência de tipo bem-sucedida para cada expressão, sem a necessidade de nenhuma anotação de tipo). As extensões que quebram a digitação principal (das quais existem muitas) também quebram a integridade da inferência de tipo.