In GHCi, the kind of FUN is displayed like this:
λ> :k FUN
FUN :: forall (n :: Multiplicity) -> * -> * -> *
At first, I thought this was a roundabout way of saying
FUN :: Multiplicity -> * -> * -> *
but it turns out Template Haskell has a separate constructor for this form: ForallVisT. I can't find any documentation on it, and I have no idea how to even begin experimenting with it in a meaningful way.
What does this syntax mean? How does forall a -> b differ from a "normal" forall a. a -> b?
forall a -> _ is used when the result type depends on an explicit argument.
-- type NonDep :: Type -> Type; argument is explicit
data NonDep (x :: Type) :: Type
-- type ImpDep :: forall a. Maybe a -> Type; first argument is implicit and dependent
data ImpDep (x :: Maybe a) :: Type
-- so if you want an explicit and dependent argument...
-- type ExpDep :: forall (a :: Type) -> Maybe a -> Type
data ExpDep (a :: Type) (x :: Maybe a) :: Type
It is odd that FUN's type has forall (m :: Multiplicity) -> and not Multiplicity -> as the following arguments (two implicit RuntimeReps and two TYPEs) do not depend on it, but such is the weirdness that surrounds GHC primitives.
Related
When having a parametrized type:
data A a=X a| Y
I have tried (successfully) implementing Functor and Applicative without specifiying the type parameter:
instance Functor A where instead of instance Functor (A a) where.Why does it work ? Looking in LYAH it seems all examples specify the type parameter in all their typeclass instances.
When should you neglect the type parameter ?
instance Functor A where instead of instance Functor (A a) where.
Why does it work ?
I find this easier to understand using GHC's kinding system. Let's start from a simple case, and experiment in GHCi:
> :k Eq Int
Eq Int :: Constraint
This tells us that Eq Int is a constraint, some property that might be verified during type checking. Indeed, if we type check (12 :: Int) == (42 :: Int), the compiler will verify that integers can be compared, resolving the constraint Eq Int.
What is Eq alone, the name of the class without the Int parameter?
> :k Eq
Eq :: * -> Constraint
This tells us that Eq can be thought of a function from types (* is the kind of types) to constraint.
Indeed, in Eq Int, Int is a type, so we have Int :: * making Int a well-kinded argument to pass to Eq.
Enough of type classes, what about type constructors?
> :k Maybe Int
Maybe Int :: *
No surprise, Maybe Int is a type
> :k Maybe
Maybe :: * -> *
Maybe instead, is a function from types to types (*->*). This is indeed what the Maybe type constructor does: mapping a type (Int) to a type (Maybe Int).
Back to the original question. Why can't we write instance Functor (A a) but we can instead write instance Functor A? Well, we have that
> :k A Int
A Int :: *
> :k A
A :: * -> *
and, most importantly,
> :k Functor
Functor :: (* -> *) -> Constraint
This tells us the the kind of the Functor type class is not the same kind of the Eq type class. Eq expects a type as an argument, while Functor expects something of kind (* -> *) as an argument. A fits that kind, while A Int does not.
This happens when, in the definition of the class, the argument is applied to some other type. E.g.
class C1 a where
foo :: a -> Bool
results in C1 :: * -> Constraint. Instead,
class C2 f where
bar :: f Int -> Bool
results in C2 :: (* -> *) -> Constraint, since f is not itself used as a type, f Int is, so f must be a parameterized type of kind * -> *.
When should you neglect the type parameter?
The type parameter is not "neglected". Let us first take a look at the Functor type class:
class Functor f where
fmap :: (a -> b) -> f a -> f b
Notice the f a and f b in the type signature. We thus here "construct types" for the type signature of fmap.
Here f is thus basically a function that takes a type and transforms it into a type. For example if f ~ A if a ~ Int, then f a generates the A Int type.
Learn You a Haskell for the Greater Good! actually explains this in its chapter about Functors, Applicatives and Monoids:
Many times, we want to make our types instances of certain type
classes, but the type parameters just don't match up for what we want
to do. It's easy to make Maybe an instance of Functor, because
the Functor type class is defined like this:
class Functor f where
fmap :: (a -> b) -> f a -> f b
So we just start out with:
instance Functor Maybe where
And then implement fmap. All the type parameters add up because the Maybe takes the place of f in
the definition of the Functor type class and so if we look at fmap
like it only worked on Maybe, it ends up behaving like:
fmap :: (a -> b) -> Maybe a -> Maybe b
(...)
i'm unclear about how to write function signatures in haskell, especially using Maybe. consider:
f :: Maybe a -> Maybe a
f = \a -> a
main = print (f (Just 5))
this works but why can't the function signature just be this?
f :: Maybe -> Maybe
since f just takes a Maybe type and returns a Maybe type.
related: if i wanted to have the Maybe type be more specific and be a Maybe Int, why doesn't this work?
f :: Maybe Int a -> Maybe Int a
f = \a -> a
main = print (f (Just (Int 5)))
(i'm running all code using runhaskell test.hs)
Seems like you are confused about type variables. First of all, in
f :: Maybe a -> Maybe a
f = \a -> a
the a's in the first line have nothing to do with the a's in the second line, we could have written:
f :: Maybe a -> Maybe a
f = \x -> x
or even
f :: Maybe foo -> Maybe foo
f = \bar -> bar
The a's are variables that stand for types. So f here is declaring that f has a whole bunch of types at once:
f :: Maybe Int -> Maybe Int
f :: Maybe String -> Maybe String
f :: Maybe (Maybe Bool) -> Maybe (Maybe Bool)
...
and so on. It is not some "labeling" of the arguments as I suspect you think. The fact that the two a's are the same means that the argument type has to be the same result type. If we had said f :: Maybe a -> Maybe b we would get this family:
f :: Maybe Int -> Maybe Bool
f :: Maybe String -> Maybe String
f :: Maybe (Maybe Bool) -> Maybe Int
...
that is, the a and b can now stand for different types, but the argument and result still have to be Maybe.
The reason you can't say
f :: Maybe -> Maybe
is because Maybe is not a type -- it is a type constructor. If you give it a type, it gives you back a type. So Maybe Int and Maybe String are types, and in general Maybe a is a type as long as a is a type.
Maybe Int a (which is parsed (Maybe Int) a) has no meaning because Maybe Int is not a type constructor -- it does not accept any more arguments.
Suggested reading: Types and Typeclasses from LYAH.
Maybe is a type constructor, essentially a type-level function. It takes a type (such as Int) and returns a type (such as Maybe Int). The “types” of types are called kinds: the kind of a type that has values, like Int, is called *. The kind of a type constructor that takes one argument is * -> *. You can see this in GHCi with the :kind/:k command:
> :k Int
Int :: *
> :k Maybe
Maybe :: * -> *
> :k Either
Either :: * -> * -> *
In a signature like Maybe a -> Maybe a, a is a type variable that gets replaced with a particular type when you call the function. (Implicitly, this means forall a. Maybe a -> Maybe a, which you can write yourself if you enable extensions such as ExplicitForall or ScopedTypeVariables.)
So if you call f :: Maybe a -> Maybe a on a Maybe Int, then f has the type Maybe Int -> Maybe Int at that call site, because a has been instantiated to Int.
The compiler rejects Maybe Int a because you’re supplying two parameters to Maybe when it only accepts one. (The a is not a name for the argument, but a parameter of the type.) Likewise, it rejects Maybe -> Maybe because you’ve given Maybe no arguments, so you’re trying to pass two types of kind * -> * to the function arrow constructor (->), which takes arguments of kind *:
> :k (->)
(->) :: * -> * -> *
As an aside, it is possible to write something like Maybe -> Maybe and have it expand to Maybe a -> Maybe a, and this can be useful sometimes, but it’s almost certainly not what you’re intending to do right now.
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeOperators #-}
type (~>) f g = forall a. f a -> g a
f :: Maybe ~> Maybe
f x = x
Here, the type synonym Maybe ~> Maybe expands to forall a. Maybe a -> Maybe a, which can be abbreviated to Maybe a -> Maybe a, the signature you wrote before.
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.
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, 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) is equivalent to 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. p a, forall a. q a) ~ forall a. (p a, q a). 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.
Prelude> :i ($)
($) ::
forall (r :: GHC.Types.RuntimeRep) a (b :: TYPE r).
(a -> b) -> a -> b
-- Defined in ‘GHC.Base’
infixr 0 $
How is it different from (a -> b) -> a -> b? Is there any b that does not fit the new type signature?
Before 8.0, there was a special case in the typechecker to make applications of $ to unlifted kinds work. This also meant that you couldn't define your own functions which could work with both lifted and unlifted kinds. Now that this so-called Levity Polymorphsim ('levity' refers to 'the degree to which something is lifted' - or 'lifted-ness', because of 'unlifted' and 'lifted' types) is built into the typechecker, this is possible:
import GHC.Exts (TYPE, RuntimeRep(..))
import Data.Kind (type (*))
ap :: forall (a :: *) (b :: *) . (a -> b) -> (a -> b)
ap f x = f x
ap_LP :: forall (a :: *) (b :: TYPE r) . (a -> b) -> (a -> b)
ap_LP f x = f x
and indeed the $ function is now defined identically to ap_LP, with no special case needed in the typechecker to make $ work with functions returning unlifted types (there is a still a special case in the typechecker to make polymorphic application, i.e. runST $ ... work, but this is unrelated to levity polymorphism). This is essentially the reason for the added complexity - there are fewer 'hacks' in the type system now, and users of GHC can take advantage of levity polymorphism just by giving a function the appropriate type (note that levity-polymorphic types are never inferred, as far as I can tell). Before levity polymorphism, if you wanted to write a polymorphic function which could possible work on both lifted and unlifted kinds, you were obligated to write two identical copies of the function with different type signatures.
The new type differs from the old one in that the new type is strictly more general than the old one:
-- ok
ap' :: forall (a :: *) (b :: *) . (a -> b) -> (a -> b)
ap' = ap_LP
-- type error:
-- * Couldn't match a lifted type with an unlifted type
ap_LP' :: forall (a :: *) (b :: TYPE r) . (a -> b) -> (a -> b)
ap_LP' = ap
In other words, every b which 'fit' the old signature must (by definition) fit the new type signature (and so this change is perfectly backwards-compatible!).
Also note that the following is not possible:
ap'' :: forall (a :: TYPE r) (b :: *) . (a -> b) -> (a -> b)
ap'' f x = f x
The error produced is
A representation-polymorphic type is not allowed here:
Type: a
Kind: TYPE r
In the type of binder `x'
and SPJ explains the reason for the restriction here:
It's absolutely right that the second argument to ($) must not have an
unboxed kind. Because the code for ($) must move that argument around
(pass to the function), so it must know its width, pointerhood ect.
But actually it would be ok for the result of the call (f $ x) to be
unboxed, because the code for ($) doesn't mess with the result; it
just tail-calls f.
This is to say that not every levity-polymorphic type has a valid inhabitant - and this relates to the operational distinction between unboxed and boxed types, which can only be treated uniformly in certain cases, and the typechecker makes sure of it.
I would like to use heterogeneous lists of lists. To this effect, I define a simple algebraic data type:
data T = LInt [Int]
| LChar [Char]
deriving (Eq, Ord, Show)
so I can now have something like this:
x = [LInt [1, 2, 3], LChar "test"]
My question: can this type be made an instance of Functor? This would be useful; for example to select elements of a list in x, as in
fmap (!!2) LChar "test" => 's'
It seems to me that this is not possible. Aside from the motivation for the question, I believe the answer would help me understand Algebraic Data Types better.
Short Answer:
No, it can't be made into a Functor.
Long Answer:
The first reason this can not be made into a function is that functors must have the kind * -> *. Kinds are like the types of types, you can even check them in GHCi using :kind <type>. For example:
> :kind Int
Int :: *
> :kind []
[] :: * -> *
> :kind Num
Num :: * -> Constraint
> :kind Maybe
Maybe :: * -> *
> :kind Either
Either :: * -> * -> *
> :kind Functor
Functor :: (* -> *) -> Constraint
The * basically means a fully applied type, such as Int, Char, [String], etc, and something like * -> * means the type takes a single type of kind * to return a new type of kind *. Constraints also have kinds, namely that they return the kind Constraint when fully applied.
Your type has kind *, which does not match * -> * required as the argument to Functor. In order for it to become a Functor it would need to accept a type variable. Adding a type variable here doesn't make much sense, but you could have
data T a = LInt [a] | LChar [a]
But this isn't very useful, we now can't enforce that LInt only contains Ints and LChar only contains Chars. Worse still, looking at the type of fmap we have
class Functor f where
fmap :: (a -> b) -> (f a -> f b)
But what you're wanting to do is something like
myfmap :: (a -> b) -> (f a -> b)
Notice how the return type is b instead of f b. The fmap function only transforms values inside a container, it doesn't extract values from said container.
It would be possible to write a parameterized type that is constrained using -XGADTs, though, you could write
data T a where
LInt :: [Int] -> T Int
LChar :: [Char] -> T Char
And this would guarantee the types are sane, but it's still not possible to make this into an instance of Functor (that satisfies the functor laws, that is) and it would prevent you from making a heterogeneous list (T Int /~ T Char).
So it really looks like the Functor option is just right out. You might find it tempting to write a function like
tmap :: ([a] -> b) -> T -> b
tmap f (LInt x) = f x
tmap f (LChar x) = f x
But this won't work either. The type system sees that you're trying to say that f :: [Int] -> b and f :: [Char] -> b, which can't be unified. You can do this by enabling -XRankNTypes though:
tmap :: (forall a. [a] -> b) -> T -> b
tmap f (LInt x) = f x
tmap f (LChar x) = f x
And this does allow you to do something like
> tmap length (LInt [1, 2, 3])
3
> tmap length (LChar "test")
4
But it won't let you do
> tmap (!! 2) (LChar "test")
Couldn't match type 'b' with 'a'
because type variable 'a' would escape its scope
This (rigid, skolem) type variable is bound by
a type expected by the context: [a] -> b
Expected type: [a] -> b
Actual type: [a] -> a
...
What this means is that the type a can't appear anywhere in the output type b, since the f passed in has to work for all a, it can't work for just any a.
In conclusion, without having to dip even further into type system madness your type can't be made to do what you want it to. You're going to have to write specialized functions to handle each case individually, which is pretty much the point of ADTs. The compiler can ensure that you do actually handle each case, and so long as you stay away from functions that return undefined or call error, then your program will be safe. It may not be as flexible as you'd like, but it'll be rock solid in terms of safety.
No because it doesn't have the right kind. Functors should have kind * -> * while T has kind *. Functors must be type constructors with a single type argument, for example IO, Maybe, Either a. This is reflected in the type of fmap:
fmap :: Functor f => (a -> b) -> f a -> f b
so f requires a type argument a. There is no such parameter for your type T.