defining haskell functions that have Maybe in signature - haskell

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.

Related

What does the `forall a -> b` syntax mean?

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.

Why does parametrized type instance works without specifying type parameter

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
(...)

In Haskell, are "higher-kinded types" *really* types? Or do they merely denote collections of *concrete* types and nothing more?

Paramametrically polymorphic functions
Consider the following function:
f :: a -> Int
f x = (1 :: Int)
We might say that the type of f is a -> Int, and that f therefore is of a "polymorphic" type.
Which of the following is the most accurate way to think about f?
There is in fact a single f of type a -> Int. It can be used, however, as an f :: Int -> Int, as an f :: Double -> Int, and so forth.
Literally speaking, the type of f is NOT a -> Int. Indeed, that is just a shorthand way of saying that there is a family of functions f whose type is concrete (i.e., there is an f :: Int -> Int, an f :: Double -> Double, and so forth; moreover, each of these functions is distinct from each other).
Higher Kinded Types
Similarly, we can consider the following type declaration:
data Maybe a = Just a | Nothing
And ask which of the two views is more correct:
There is no single type Maybe; indeed, there is merely a family of concrete types (Maybe Int, Maybe String, etc) and nothing more.
There is in fact a single type Maybe. This type is a higher-kinded type. When we say that it is a "type" we mean it literally (not as a shorthand for (1)). It just so happens that we can also write Maybe Int, Maybe Double, and so forth to generate distinct types (which happen to be concrete). But, at the end of the day (i.e.): Maybe, Maybe Int, and Maybe String denote three distinct types, two of which are concrete and one of which is higher-kinded.
Question Summary
In Haskell, are "higher-kinded types" really types? Or are only concrete types "the real types", and when we speak of "higher-kinded types" we are merely denoting a family of concrete types. Moreover, do paramametrically polymorphic functions denote functions of a single type, or do they merely denote a collection functions of concrete types (and nothing more)?
It's not entirely clear what you want to ask, and what is the practical difference between 1 and 2 in both cases, but from an underlying math perspective:
Parametrically Polymorphic Functions
f actually has type f :: forall a.a->int
It is a perfectly legal type for a function in typed lambda calculus, which Haskell is based on. It can be something like:
f = λa:Type.λx:a.(body for f)
How do you get Double->Int from it? You apply it to Double type:
f Double = (λa:Type.λx:a.(body for f)) Double => λx:Double.(body for f|a=Double)
Haskell does both operations (type abstraction and type application) behind the scene, although it is possible to explicitly state forall part in the type signature with XExplicitForAll GHC extension, and explicitly make a Double->Int instance of f with type signature:
f_double :: Double -> Int
f_double = f
Higher Kinded Types
Consider a simple type:
data Example = IntVal Int | NoVal
(Yes, it is Maybe Int).
Maybe is a type constructor, just like IntVal is a data constructor. It is exactly the same thing, only 'one level higher', in the sense that Maybe is applied to Type, much like IntVal is applied to Int.
In lambda calculus, Maybe has type:
Maybe : Type->Type
Haskell doesn't allow you to get a type from type constructor, but allows you to get a kind (which is just a fancy name for type of type):
:k Maybe
Maybe :: * -> *
So no, Maybe is not a type: you can't have an object with the type Maybe. Maybe is (almost) a function from types to types, like IntVal is a function from values to values.
We call the result of applying Maybe to String as Maybe String, like we call the result of applying IntVal to 4 as IntVal 4.
First a question: Is the statement "all lists have length" a single statement or a series of statements "list1 has length", "list2 has length",...?
If you give the type of f with explicit forall, you get f :: forall a. a -> Int. First of all, this is not "higher-kinded". We can do the following in GHCI:
λ> :set -XRankNTypes
λ> :k (forall a. a -> Int)
(forall a. a -> Int) :: *
So f has a kind of *.
Now, in Haskell, we can use ~ for type equality. We can set the following to check stuff in GHCI:
λ> :set -XImpredicativeTypes
λ> :set -XTypeFamilies
λ> :t undefined :: ((~) Int Int) => a
undefined :: ((~) Int Int) => a :: a
This shows that GHC figured out type equality for this example. Type inequality will give the following error:
λ> undefined :: ((~) (Int -> Int) (Int)) => a
<interactive>:22:1:
Couldn't match expected type ‘Int’ with actual type ‘Int -> Int’
In the expression: undefined :: ((~) (Int -> Int) (Int)) => a
In an equation for ‘it’:
it = undefined :: ((~) (Int -> Int) (Int)) => a
Now using this method directly will prevent us from comparing the type of f, but I found a slight variant that should work for our purposes:
λ> :t undefined :: forall a. ((a -> Int) ~ (Int -> Int)) => a
undefined :: forall a. ((a -> Int) ~ (Int -> Int)) => a :: Int
In other words, if f is type-equivalent to g :: Int -> Int, then a must be Int. This is similar to x = y, y = 0 so x = 0. We don't have x = 0 until we specify y = 0, until then we just have x = y.
Maybe is different because it has the following kind:
λ> :k Maybe
Maybe :: * -> *
Because we're using DataKinds, we have :k (~) :: k -> k -> GHC.Prim.Constraint, so we can do things like:
λ> :t undefined :: (~) Maybe Maybe => Int
undefined :: (~) Maybe Maybe => Int :: Int
λ> :k Either ()
Either () :: * -> *
λ> :t undefined :: (~) Maybe (Either ()) => Int
Couldn't match expected type ‘Either ()’ with actual type ‘Maybe’
To sum up, f :: forall a. a -> Int makes as much sense as the statement "if you give me anything, I'll give you an Int". Could you translate the statement into a bunch of statements "if you give me a dog..", "if you give me a penny.."? Yeah, but it weakens the statement. At the end, decide precisely what you mean by the "same" and you get your answer.

Functor instance for a simple algebraic data type

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.

How to query the unification type to ghci?

It is possible to query ghci for an unification type?
For example, if I want to know the type of the unification between (Int -> Bool) and (a -> Bool) how can I query this to ghci?
What I'm trying to solve is the exercise 13.23 from third edition of Haskell: The Craft of Functional Programming.
How can you use the Haskell system to check whether two type expressions
are unifiable, and if so what is their unification? Hint: you can make dummy
definitions in Haskell in which the defined value, zircon say, is equated with
itself:
zircon = zircon
Values defined like this can be declared to have any type you wish.
Thanks,
Sebastián.
One way is to use asTypeOf:: a -> a -> a. As a function, asTypeOf isn't very interesting, but its type is nice: it forces its two arguments and its return type to unify. So:
> :t asTypeOf (undefined :: Int -> Bool) (undefined :: a -> Bool)
asTypeOf (undefined :: Int -> Bool) (undefined :: a -> Bool)
:: Int -> Bool
So you can see that those two types unified to Int -> Bool. For a slightly more interesting example, let's unify Maybe a and f (Bool, c):
> :t asTypeOf (undefined :: Maybe a) (undefined :: f (Bool, c))
asTypeOf (undefined :: Maybe a) (undefined :: f (Bool, c))
:: Maybe (Bool, c)
On the other hand, for the purpose of exercises, I encourage you to attempt to do the unification by hand. It's not hard, once you get the hang of it, and is a skill that you will use over and over.

Resources