Abstract data types in a type class definition - haskell

I'm trying to understand what's happening with the type s below:
class A a where
f :: a -> s
data X = X
instance A X where
f x = "anything"
I expected this to work, thinking that since type s isn't bound to anything, it could be anything. But the compiler says that it "Couldn't match expected type ‘s’ with actual type ‘[Char]’", as if type s was a fixed type like Int, Char…
So my second interpretation was to say that, since we don't know anything about s in the type class declaration, we cannot tell when making X an instance of A if the return value of the function f we give matches type s or not. But there are type classes that use abstract data types that are not bound to anything without problems, like Functor:
class Functor f where
fmap :: (a -> b) -> f a -> f b
Why is the type s above a problem when types a and b here aren't?

You're trying to express this:
f :: a -> ∃s . s
...but what the signature you've written says is actually
f :: a -> ∀s . s
What does all of that mean?
The existential type ∃s . s means, the functions may return a value of some type, i.e. “there exists a type s such that the function returns an s value”.This is not supported by the Haskell language, because it turns out to be pretty useless.
The universal type ∀s . s means, the function is able to produce a value of any type, i.e. “for all types s, the function can return an s value”.
The latter is very useful; fmap is actually a good example: that function works, no matter what types a and b are, and the user is always guaranteed that the result will actually have the desired type, namely f b.
But that means you can't just pick some particular type in the implementation, like you did with String. ...Well, actually you can do that, but only by wrapping the existential in a data type:
{-# LANGUAGE ExistentialQuantification, UnicodeSyntax #-}
data Anything = ∀ s . Anything s
class A a where
f :: a -> Anything
instance A X where
f x = Anything "anything"
...but as I said, this is almost completely useless, because when somebody wants to use that instance they'll have no way to know what particular type the wrapped result value has. And there is nothing you can do with a value of completely unknown type.

Related

How to write this simple Monad?

I try to write this:
data A=A Int deriving Show
instance Monad A where
return x=A x
A x>>=f=f x
main=print a where a=A 1
I learn it from the book 《Learn You a Haskell for Great Good》:
instance Monad Maybe where
return x = Just x
Nothing >>= f = Nothing
Just x >>= f = f x
fail _ = Nothing
but got error:
a.hs:3:16: error:
? Expected kind ‘* -> *’, but ‘A’ has kind ‘*’
? In the first argument of ‘Monad’, namely ‘A’
In the instance declaration for ‘Monad A’
so how to write it? When finish, I can write
A 1>>\x->x+1
and get A 2
You can't make A an instance of Monad given its current definition.
The error message tells you that the compiler expects something of the kind * -> *. This means a type that takes a type as input, like Maybe a, IO a, or [] a. In other words, the type must be parametrically polymorphic.
In oder to get an intuitive sense of this, consider return, which has the type:
return :: a -> m a
The type argument a is unconstrained. This means that you should be able to take any value of type a and turn it into a value of the polymorphic type.
If I give you the Boolean value False, which A value will you construct from it? If I give you the string "foo", which A value will you construct from it? If I give you the function id, which A value will you construct from it?
If you want to make your type a Monad instance, you must give it a type parameter, at least like this:
data A a = A Int deriving Show
Here, the a type parameter is in the phantom role; it's not used, but now you're at least able to make it a Functor. This version of A is isomorphic to the Const functor. You can make it a Functor and Applicative instance, but can you make it a Monad?

Why is it said that typeclasses are existential?

According to this link describing existential types:
A value of an existential type like ∃x. F(x) is a pair containing some type x and a value of the type F(x). Whereas a value of a polymorphic type like ∀x. F(x) is a function that takes some type x and produces a value of type F(x). In both cases, the type closes over some type constructor F.
But a function definition with type class constraints doesn't pair with the type class instance.
It's not forall f, exists Functor f, ... (because it's obvious not every type f has instance of Functor f, hence exists Functor f ... not true).
It's not exists f and Functor f, ... (because it's applicable to all instances of satisfied f, not only the chosen one).
To me, it's forall f and instances of Functor f, ..., more like to scala's implicit arguments rather than existential types.
And according to this link describing type classes:
[The class declaration for Eq] means, logically, there is a type a for which the type a -> a -> Bool is inhabited, or, from a it can be proved that a -> a -> Bool (the class promises two different proofs for this, having names == and /=). This proposition is of existential nature (not to be confused with existential type)
What's the difference between type classes and existential types, and why are they both considered "existential"?
The wiki you quote is wrong, or at least being imprecise. A class declaration is not an existential proposition; it is not a proposition of any kind, it is merely a definition of a shorthand. One could then move on to making a proposition using that definition if you wanted, but on its own it's nothing like that. For example,
class Eq a where (==) :: a -> a -> Bool
makes a new definition. One could then write a non-existential, non-universal proposition using it, say,
Eq ()
which we could "prove" by writing:
instance Eq () where () == () = True
Or one could write
prop_ExistsFoo :: exists a. Eq a *> a
as an existential proposition. (Haskell doesn't actually have the exists proposition former, nor (*>). Think of (*>) as dual to (=>) -- just like exists is dual to forall. So where (=>) is a function which takes evidence of a constraint, (*>) is a tuple that contains evidence of a constraint, just like forall is for a function that takes a type while exists is for a tuple that contains a type.) We could "prove" this proposition by, e.g.
prop_ExistsFoo = ()
Note here that the type contained in the exists tuple is (); the evidence contained in the (*>) tuple is the Eq () instance we wrote above. I have honored Haskell's tendency to make types and instances silent and implicit here, so they don't appear in the visible proof text.
Similarly, we could make a different, universal proposition out of Eq by writing something like
prop_ForallEq :: forall a. Eq a => a
which is not nontrivially provable, or
prop_ForallEq2 :: forall a. Eq a => a -> a -> Bool
which we could "prove", for example, by writing
prop_ForallEq2 x y = not (x == y)
or in many other ways.
But the class declaration in itself is definitely not an existential proposition, and it doesn't have "existential nature", whatever that is supposed to mean. Instead of getting hung up and confused on that, please congratulate yourself for correctly labeling this incorrect claim as confusing!
The second quote is imprecise. The existential claim comes with the instances, not with the class itself. Consider the following class:
class Chaos a where
to :: a -> y
from :: x -> a
While this is a perfectly valid declaration, there can't possibly be any instances of Chaos (it there were, to . from would exist, which would be quite amusing). The type of, say, to...
GHCi> :t to
to :: Chaos a => a -> y
... tells us that, given any type a, if a is an instance of Chaos, there is a function which can turn an a into a value of any type whatsoever. If Chaos has no instances, that statement is vacuously true, so we can't infer the existence of any such function from it.
Putting classes aside for a moment, this situation is rather similar to what we have with the absurd function:
absurd :: Void -> a
This type says that, given a Void value, we can produce a value of any type whatsoever. That sounds, well, absurd -- but then we remember that Void is the empty type, which means there are no Void values, and it's all good.
For the sake of contrast, we might note that instances become possible once we break Chaos apart in two classes:
class Primordial a where
conjure :: a -> y
class Doom a where
destroy :: x -> a
instance Primordial Void where
conjure = absurd
instance Doom () where
destroy = const ()
When we, for example, write instance Primordial Void, we are claiming that Void is an instance of Primordial. That implies there must exist a function conjure :: Void -> y, at which point we must back up the claim by supplying an implementation.

Haskell function returning existential type

Is it possible to write a Haskell function that yields a parameterised type where the exact type parameter is hidden? I.e. something like f :: T -> (exists a. U a)? The obvious attempt:
{-# LANGUAGE ExistentialQuantification #-}
data D a = D a
data Wrap = forall a. Wrap (D a)
unwrap :: Wrap -> D a
unwrap (Wrap d) = d
fails to compile with:
Couldn't match type `a1' with `a'
`a1' is a rigid type variable bound by
a pattern with constructor
Wrap :: forall a. D a -> Wrap,
in an equation for `unwrap'
at test.hs:8:9
`a' is a rigid type variable bound by
the type signature for unwrap :: Wrap -> D a at test.hs:7:11
Expected type: D a
Actual type: D a1
In the expression: d
In an equation for `unwrap': unwrap (Wrap d) = d
I know this is a contrived example, but I'm curious if there is a way to convince GHC that I do not care for the exact type with which D is parameterised, without introducing another existential wrapper type for the result of unwrap.
To clarify, I do want type safety, but also would like to be able to apply a function dToString :: D a -> String that does not care about a (e.g. because it just extracts a String field from D) to the result of unwrap. I realise there are other ways of achieving it (e.g. defining wrapToString (Wrap d) = dToString d) but I'm more interested in whether there is a fundamental reason why such hiding under existential is not permitted.
Yes, you can, but not in a straightforward way.
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE RankNTypes #-}
data D a = D a
data Wrap = forall a. Wrap (D a)
unwrap :: Wrap -> forall r. (forall a. D a -> r) -> r
unwrap (Wrap x) k = k x
test :: D a -> IO ()
test (D a) = putStrLn "Got a D something"
main = unwrap (Wrap (D 5)) test
You cannot return a D something_unknown from your function, but you can extract it and immediately pass it to another function that accepts D a, as shown.
Yes, you can convince GHC that you do not care for the exact type with which D is parameterised. Just, it's a horrible idea.
{-# LANGUAGE GADTs #-}
import Unsafe.Coerce
data D a = D a deriving (Show)
data Wrap where -- this GADT is equivalent to your `ExistentialQuantification` version
Wrap :: D a -> Wrap
unwrap :: Wrap -> D a
unwrap (Wrap (D a)) = D (unsafeCoerce a)
main = print (unwrap (Wrap $ D "bla") :: D Integer)
This is what happens when I execute that simple program:
and so on, until memory consumption brings down the system.
Types are important! If you circumvent the type system, you circumvent any predictability of your program (i.e. anything can happen, including thermonuclear war or the famous demons flying out of your nose).
Now, evidently you thought that types somehow work differently. In dynamic languages such as Python, and also to a degree in OO languages like Java, a type is in a sense a property that a value can have. So, (reference-) values don't just carry around the information needed to distinguish different values of a single type, but also information to distinguish different (sub-)types. That's in many senses rather inefficient – it's a major reason why Python is so slow and Java needs such a huge VM.
In Haskell, types don't exist at runtime. A function never knows what type the values have it's working with. Only because the compiler knows all about the types it will have, the function doesn't need any such knowledge – the compiler has already hard-coded it! (That is, unless you circumvent it with unsafeCoerce, which as I demonstrated is as unsafe as it sounds.)
If you do want to attach the type as a “property” to a value, you need to do it explicitly, and that's what those existential wrappers are there for. However, there are usually better ways to do it in a functional language. What's really the application you wanted this for?
Perhaps it's also helpful to recall what a signature with polymorphic result means. unwrap :: Wrap -> D a doesn't mean “the result is some D a... and the caller better don't care for the a used”. That would be the case in Java, but it would be rather useless in Haskell because there's nothing you can do with a value of unknown type.
Instead it means: for whatever type a the caller requests, this function is able to supply a suitable D a value. Of course this is tough to deliver – without extra information it's just as impossible as doing anything with a value of given unknown type. But if there are already a values in the arguments, or a is somehow constrained to a type class (e.g. fromInteger :: Num a => Integer -> a, then it's quite possible and very useful.
To obtain a String field – independent of the a parameter – you can just operate directly on the wrapped value:
data D a = D
{ dLabel :: String
, dValue :: a
}
data Wrap where Wrap :: D a -> Wrap
labelFromWrap :: Wrap -> String
labelFromWrap (Wrap (D l _)) = l
To write such functions on Wrap more generically (with any “ label accesor that doesn't care about a”), use Rank2-polymorphism as shown in n.m.'s answer.

What does Functor's fmap tell about types?

What does f a and f b tell me about its type?
class Functor f where
fmap :: (a -> b) -> f a -> f b
I think I get the idea behind standard instances of a functor. However I'm having hard time understanding what f a and f actually represent.
I understand that f a and f b are just types and they must carry information what type constructor was used to create them and type arguments that were used.
Is f a type constructor of kind * -> *? Is (->) r a type constructor just like Maybe is?
I understand that f a and f b are just types and they must carry information what type constructor was used to create them and type arguments that were used.
Good explanation.
Is f a type constructor of kind * -> *?
In effect.
Is (->) r a type constructor just like Maybe is?
In effect, yes:
Yes in the sense that you can apply it to a type like String and get r -> String, just like you can apply Maybe to String to get Maybe String. You can use for f anything that gives you a type from any other type.
..but no...
No, in the sense that Daniel Wagner points out; To be precise, Maybe and [] are type constructors, but (->) r and Either a are sort of like partially applied type constructors. Nevertheless they make good functors, because you can freely apply functions "inside" them and change the type of "the contents".
(Stuff in inverted commas is very hand-wavy imprecise terminology.)
My (possibly mildly tortured) reading of chapter 4 of the Haskell 2010 Report is that Maybe and (->) r are both types, of kind * -> *. Alternatively, the Report also labels them as type expressions—but I can't discern a firm difference in how the Report uses the two terms, except perhaps for surface syntax details. (->) and Maybe are type constructors; type expressions are assembled from type constructors and type variables.
For example, section 4.1.1 ("Kinds") of the 2010 report says (my boldface):
To ensure that they are valid, type expressions are classified into different kinds, which take one of two possible forms:
The symbol ∗ represents the kind of all nullary type constructors.
If κ1 and κ2 are kinds, then κ1 → κ2 is the kind of types that take a type of kind κ1 and return a type of kind κ2.
Section 4.3.2, "Instance Declarations" (my boldface):
An instance declaration that makes the type T to be an instance of class C is called a C-T instance declaration and is subject to these static restrictions:
A type may not be declared as an instance of a particular class more than once in the program.
The class and type must have the same kind; this can be determined using kind inference as described in Section 4.6.
So going by that language, the following instance declaration makes the type (->) r to be an instance of the class Functor:
instance Functor ((->) r) where
fmap f g = f . g
The funny thing about this terminology is that we call (->) r a "type" even though there are no expressions in Haskell that have that type—not even undefined:
foo :: (->) r
foo = undefined
{-
[1 of 1] Compiling Main ( ../src/scratch.hs, interpreted )
../src/scratch.hs:1:8:
Expecting one more argument to `(->) r'
In the type signature for `foo': foo :: (->) r
-}
But I think that's not a big deal. Basically, all declarations in Haskell must have types of kind *.
As a side note, from my limited understanding of dependently typed languages, many of these lack Haskell's firm distinction between terms and types, so that something like (->) Boolean is an expression whose value is a function that takes a type as its argument and produces a type as its result.

What is the purpose of Rank2Types?

I am not really proficient in Haskell, so this might be a very easy question.
What language limitation do Rank2Types solve? Don't functions in Haskell already support polymorphic arguments?
It's hard to understand higher-rank polymorphism unless you study System F directly, because Haskell is designed to hide the details of that from you in the interest of simplicity.
But basically, the rough idea is that polymorphic types don't really have the a -> b form that they do in Haskell; in reality, they look like this, always with explicit quantifiers:
id :: ∀a.a → a
id = Λt.λx:t.x
If you don't know the "∀" symbol, it's read as "for all"; ∀x.dog(x) means "for all x, x is a dog." "Λ" is capital lambda, used for abstracting over type parameters; what the second line says is that id is a function that takes a type t, and then returns a function that's parametrized by that type.
You see, in System F, you can't just apply a function like that id to a value right away; first you need to apply the Λ-function to a type in order to get a λ-function that you apply to a value. So for example:
(Λt.λx:t.x) Int 5 = (λx:Int.x) 5
= 5
Standard Haskell (i.e., Haskell 98 and 2010) simplifies this for you by not having any of these type quantifiers, capital lambdas and type applications, but behind the scenes GHC puts them in when it analyzes the program for compilation. (This is all compile-time stuff, I believe, with no runtime overhead.)
But Haskell's automatic handling of this means that it assumes that "∀" never appears on the left-hand branch of a function ("→") type. Rank2Types and RankNTypes turn off those restrictions and allow you to override Haskell's default rules for where to insert forall.
Why would you want to do this? Because the full, unrestricted System F is hella powerful, and it can do a lot of cool stuff. For example, type hiding and modularity can be implemented using higher-rank types. Take for example a plain old function of the following rank-1 type (to set the scene):
f :: ∀r.∀a.((a → r) → a → r) → r
To use f, the caller first must choose what types to use for r and a, then supply an argument of the resulting type. So you could pick r = Int and a = String:
f Int String :: ((String → Int) → String → Int) → Int
But now compare that to the following higher-rank type:
f' :: ∀r.(∀a.(a → r) → a → r) → r
How does a function of this type work? Well, to use it, first you specify which type to use for r. Say we pick Int:
f' Int :: (∀a.(a → Int) → a → Int) → Int
But now the ∀a is inside the function arrow, so you can't pick what type to use for a; you must apply f' Int to a Λ-function of the appropriate type. This means that the implementation of f' gets to pick what type to use for a, not the caller of f'. Without higher-rank types, on the contrary, the caller always picks the types.
What is this useful for? Well, for many things actually, but one idea is that you can use this to model things like object-oriented programming, where "objects" bundle some hidden data together with some methods that work on the hidden data. So for example, an object with two methods—one that returns an Int and another that returns a String, could be implemented with this type:
myObject :: ∀r.(∀a.(a → Int, a -> String) → a → r) → r
How does this work? The object is implemented as a function that has some internal data of hidden type a. To actually use the object, its clients pass in a "callback" function that the object will call with the two methods. For example:
myObject String (Λa. λ(length, name):(a → Int, a → String). λobjData:a. name objData)
Here we are, basically, invoking the object's second method, the one whose type is a → String for an unknown a. Well, unknown to myObject's clients; but these clients do know, from the signature, that they will be able to apply either of the two functions to it, and get either an Int or a String.
For an actual Haskell example, below is the code that I wrote when I taught myself RankNTypes. This implements a type called ShowBox which bundles together a value of some hidden type together with its Show class instance. Note that in the example at the bottom, I make a list of ShowBox whose first element was made from a number, and the second from a string. Since the types are hidden by using the higher-rank types, this doesn't violate type checking.
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ImpredicativeTypes #-}
type ShowBox = forall b. (forall a. Show a => a -> b) -> b
mkShowBox :: Show a => a -> ShowBox
mkShowBox x = \k -> k x
-- | This is the key function for using a 'ShowBox'. You pass in
-- a function #k# that will be applied to the contents of the
-- ShowBox. But you don't pick the type of #k#'s argument--the
-- ShowBox does. However, it's restricted to picking a type that
-- implements #Show#, so you know that whatever type it picks, you
-- can use the 'show' function.
runShowBox :: forall b. (forall a. Show a => a -> b) -> ShowBox -> b
-- Expanded type:
--
-- runShowBox
-- :: forall b. (forall a. Show a => a -> b)
-- -> (forall b. (forall a. Show a => a -> b) -> b)
-- -> b
--
runShowBox k box = box k
example :: [ShowBox]
-- example :: [ShowBox] expands to this:
--
-- example :: [forall b. (forall a. Show a => a -> b) -> b]
--
-- Without the annotation the compiler infers the following, which
-- breaks in the definition of 'result' below:
--
-- example :: forall b. [(forall a. Show a => a -> b) -> b]
--
example = [mkShowBox 5, mkShowBox "foo"]
result :: [String]
result = map (runShowBox show) example
PS: for anybody reading this who's wondered how come ExistentialTypes in GHC uses forall, I believe the reason is because it's using this sort of technique behind the scenes.
Do not functions in Haskell already support polymorphic arguments?
They do, but only of rank 1. This means that while you can write a function that takes different types of arguments without this extension, you can't write a function that uses its argument as different types in the same invocation.
For example the following function can't be typed without this extension because g is used with different argument types in the definition of f:
f g = g 1 + g "lala"
Note that it's perfectly possible to pass a polymorphic function as an argument to another function. So something like map id ["a","b","c"] is perfectly legal. But the function may only use it as monomorphic. In the example map uses id as if it had type String -> String. And of course you can also pass a simple monomorphic function of the given type instead of id. Without rank2types there is no way for a function to require that its argument must be a polymorphic function and thus also no way to use it as a polymorphic function.
Luis Casillas's answer gives a lot of great info about what rank 2 types mean, but I'll just expand on one point he didn't cover. Requiring an argument to be polymorphic doesn't just allow it to be used with multiple types; it also restricts what that function can do with its argument(s) and how it can produce its result. That is, it gives the caller less flexibility. Why would you want to do that? I'll start with a simple example:
Suppose we have a data type
data Country = BigEnemy | MediumEnemy | PunyEnemy | TradePartner | Ally | BestAlly
and we want to write a function
f g = launchMissilesAt $ g [BigEnemy, MediumEnemy, PunyEnemy]
that takes a function that's supposed to choose one of the elements of the list it's given and return an IO action launching missiles at that target. We could give f a simple type:
f :: ([Country] -> Country) -> IO ()
The problem is that we could accidentally run
f (\_ -> BestAlly)
and then we'd be in big trouble! Giving f a rank 1 polymorphic type
f :: ([a] -> a) -> IO ()
doesn't help at all, because we choose the type a when we call f, and we just specialize it to Country and use our malicious \_ -> BestAlly again. The solution is to use a rank 2 type:
f :: (forall a . [a] -> a) -> IO ()
Now the function we pass in is required to be polymorphic, so \_ -> BestAlly won't type check! In fact, no function returning an element not in the list it is given will typecheck (although some functions that go into infinite loops or produce errors and therefore never return will do so).
The above is contrived, of course, but a variation on this technique is key to making the ST monad safe.
Higher-rank types aren't as exotic as the other answers have made out. Believe it or not, many object-oriented languages (including Java and C#!) feature them. (Of course, no one in those communities knows them by the scary-sounding name "higher-rank types".)
The example I'm going to give is a textbook implementation of the Visitor pattern, which I use all the time in my daily work. This answer is not intended as an introduction to the visitor pattern; that knowledge is readily available elsewhere.
In this fatuous imaginary HR application, we wish to operate on employees who may be full-time permanent staff or temporary contractors. My preferred variant of the Visitor pattern (and indeed the one which is relevant to RankNTypes) parameterises the visitor's return type.
interface IEmployeeVisitor<T>
{
T Visit(PermanentEmployee e);
T Visit(Contractor c);
}
class XmlVisitor : IEmployeeVisitor<string> { /* ... */ }
class PaymentCalculator : IEmployeeVisitor<int> { /* ... */ }
The point is that a number of visitors with different return types can all operate on the same data. This means IEmployee must express no opinion as to what T ought to be.
interface IEmployee
{
T Accept<T>(IEmployeeVisitor<T> v);
}
class PermanentEmployee : IEmployee
{
// ...
public T Accept<T>(IEmployeeVisitor<T> v)
{
return v.Visit(this);
}
}
class Contractor : IEmployee
{
// ...
public T Accept<T>(IEmployeeVisitor<T> v)
{
return v.Visit(this);
}
}
I wish to draw your attention to the types. Observe that IEmployeeVisitor universally quantifies its return type, whereas IEmployee quantifies it inside its Accept method - that is to say, at a higher rank. Translating clunkily from C# to Haskell:
data IEmployeeVisitor r = IEmployeeVisitor {
visitPermanent :: PermanentEmployee -> r,
visitContractor :: Contractor -> r
}
newtype IEmployee = IEmployee {
accept :: forall r. IEmployeeVisitor r -> r
}
So there you have it. Higher-rank types show up in C# when you write types containing generic methods.
For those familiar with object oriented languages, a higher-rank function is simply a generic function that expects as its argument another generic function.
E.g. in TypeScript you could write:
type WithId<T> = T & { id: number }
type Identifier = <T>(obj: T) => WithId<T>
type Identify = <TObj>(obj: TObj, f: Identifier) => WithId<TObj>
See how the generic function type Identify demands a generic function of the type Identifier? This makes Identify a higher-rank function.

Resources