(„Java”, w znaczeniu stosowanym w niniejszym dokumencie, jest zdefiniowane jako standardowy Java SE 7 ; „Haskell”, w znaczeniu stosowanym w niniejszym dokumencie, jest zdefiniowany jako standardowy Haskell 2010 ).
Rzeczy, które ma system typów Java, ale Haskell nie:
- nominalny polimorfizm podtypu
- informacje o częściowym typie środowiska wykonawczego
Rzeczy, które ma system typów Haskella, ale Java nie:
- ograniczony polimorfizm ad-hoc
- powoduje polimorfizm podtypu „oparty na ograniczeniach”
- lepiej dobrany polimorfizm parametryczny
- podstawowe pisanie
EDYTOWAĆ:
Przykłady każdego z powyższych punktów:
Unikalny dla Java (w porównaniu do Haskell)
Nominalny polimorfizm podtypu
/* 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 */
Informacje o częściowym typie środowiska wykonawczego
/* 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'
Unikalny dla Haskell (w porównaniu z Javą)
Ograniczony polimorfizm ad-hoc
-- 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")
Polimorfizm podtypu „oparty na ograniczeniach” (oparty na ograniczonym polimorfizmie ad-hoc)
-- 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
Lepszy parametryczny polimorfizm
-- 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
Główne pisanie
Trudno podać bezpośredni przykład tego, ale oznacza to, że każde wyrażenie ma dokładnie jeden maksymalnie ogólny typ (zwany jego głównym rodzajem ), który jest uważany za kanoniczny typ tego wyrażenia. W kategoriach polimorfizmu podtypu „opartego na ograniczeniach” (patrz wyżej), głównym typem wyrażenia jest unikalny podtyp każdego możliwego typu, którego można użyć tego wyrażenia. Obecność podstawowego pisania w (nie rozwiniętym) języku Haskell pozwala na pełne wnioskowanie o typie (czyli pomyślne wnioskowanie o typie dla każdego wyrażenia, bez potrzeby adnotacji typu). Rozszerzenia, które łamią podstawowe typowanie (których jest wiele), również łamią kompletność wnioskowania o typie.