Type quantifiers in Haskell functions
Suppose I have two Haskell functions of the following types, with ExplicitForAll activated,
f :: forall a. (a -> Int)
g :: forall a. (Int -> a)
It seems to me that the type of g is isomorphic to Int -> (forall a. a) , because for example the type of g(2) is forall a. a forall a. a .
However, the type of f doesn't look isomorphic to (forall a. a) -> Int . f is a polymorphic function, it knows what to compute on each input type a , in mathematics I guess it would rather be a family of functions ; but I don't think it can handle a single argument that has all types.
Is it a rule of typed lambda calculus that type quantifiers distribute on functions target types, but not on functions source types ?
Does the type (forall a. a) -> Int exist in Haskell, possibly restrained to a type class (forall a. SomeClass a => a) -> Int ? Is it useful ?
weird :: (forall a. a) -> Int is unnecessarily specific.
undefined is the only value that has type forall a. a forall a. a , so the definiton would have to be weird _ = someInteger , which is just a more restrictive version of const .
A ∀ a . is basically just an extra implicit argument, or rather, a specification of how type-constraints pertaining to that argument should be handled. For instance,
f :: ∀ a . Show a => (a -> Int)
g :: ∀ a . Show a => (Int -> a)
are in essence functions of two arguments,
f' :: ShowDictionary a -> a -> Int
g' :: ShowDictionary a -> Int -> a
or even dumber,
type GenericReference = Ptr Foreign.C.Types.Void -- this doesn't actually exist
f'' :: (GenericReference -> String) -> GenericReference -> Int
g'' :: (GenericReference -> String) -> Int -> GenericReference
Now, these are just monomorphic (or weak-dynamic typed) functions. We can clearly use flip on them to obtain
f''' :: GenericReference -> (GenericReference -> String) -> Int
g''' :: Int -> (GenericReference -> String) -> GenericReference
The latter can simply be evaluated partially with any Int argument, hence g is indeed equivalent to γ :: Int -> (∀ a . Show a => Int -> a) .
With f''' , applying it to some void-pointered argument would be a recipe to disaster, since there's no way for the type system to ensure that the actually passed type matches the one the Show function is prepared to handle.
This is a copy of Chi's comment above, it explains the theoretical part by interpreting functions as logical implications (Curry-Howard correspondence) :
Type quantifers can be swapped with arrows as in logic: the proposition p -> forall a. q(a) p -> forall a. q(a) is equivalent to forall a. p -> q(a) forall a. p -> q(a) provided p does not depend on a . If Haskell had existential types, we would have the isomorphism (forall a. p(a) -> q) ~ ((exists a. p(a)) -> q) . It commutes with products too (forall a. pa, forall a. qa) ~ forall a. (pa, qa) (forall a. pa, forall a. qa) ~ forall a. (pa, qa) . On sums it's trickier.
I also link the specs of RankNTypes. It does enforce the rules of "floating out" type quantifiers and defines the type (forall a. SomeClass a => a) -> Int .
上一篇: RxJava2去抖功能在RecyclerView中无法正常工作
下一篇: 在Haskell函数中输入量词
