The absurd function in Data.Void has the following signature, where Void is the logically uninhabited type exported by that package:
-- | Since 'Void' values logically don't exist, this witnesses the logical
-- reasoning tool of \"ex falso quodlibet\".
absurd :: Void -> a
I do know enough logic to get the documentation's remark that this corresponds, by the propositions-as-types correspondence, to the valid formula ⊥ → a.
What I'm puzzled and curious about is: in what sort of practical programming problems is this function useful? I'm thinking that perhaps it's useful in some cases as a type-safe way of exhaustively handling "can't happen" cases, but I don't know enough about practical uses of Curry-Howard to tell whether that idea is on the right track at all.
EDIT: Examples preferably in Haskell, but if anybody wants to use a dependently typed language I'm not going to complain...
Life is a little bit hard, since Haskell is non strict. The general use case is to handle impossible paths. For example
simple :: Either Void a -> a
simple (Left x) = absurd x
simple (Right y) = y
This turns out to be somewhat useful. Consider a simple type for Pipes
data Pipe a b r
= Pure r
| Await (a -> Pipe a b r)
| Yield !b (Pipe a b r)
this is a strict-ified and simplified version of the standard pipes type from Gabriel Gonzales' Pipes library. Now, we can encode a pipe that never yields (ie, a consumer) as
type Consumer a r = Pipe a Void r
this really never yields. The implication of this is that the proper fold rule for a Consumer is
foldConsumer :: (r -> s) -> ((a -> s) -> s) -> Consumer a r -> s
foldConsumer onPure onAwait p
= case p of
Pure x -> onPure x
Await f -> onAwait $ \x -> foldConsumer onPure onAwait (f x)
Yield x _ -> absurd x
or alternatively, that you can ignore the yield case when dealing with consumers. This is the general version of this design pattern: use polymorphic data types and Void to get rid of possibilities when you need to.
Probably the most classic use of Void is in CPS.
type Continuation a = a -> Void
that is, a Continuation is a function which never returns. Continuation is the type version of "not." From this we get a monad of CPS (corresponding to classical logic)
newtype CPS a = Continuation (Continuation a)
since Haskell is pure, we can't get anything out of this type.
Consider this representation for lambda terms parametrized by their free variables. (See papers by Bellegarde and Hook 1994, Bird and Paterson 1999, Altenkirch and Reus 1999.)
data Tm a = Var a
| Tm a :$ Tm a
| Lam (Tm (Maybe a))
You can certainly make this a Functor, capturing the notion of renaming, and a Monad capturing the notion of substitution.
instance Functor Tm where
fmap rho (Var a) = Var (rho a)
fmap rho (f :$ s) = fmap rho f :$ fmap rho s
fmap rho (Lam t) = Lam (fmap (fmap rho) t)
instance Monad Tm where
return = Var
Var a >>= sig = sig a
(f :$ s) >>= sig = (f >>= sig) :$ (s >>= sig)
Lam t >>= sig = Lam (t >>= maybe (Var Nothing) (fmap Just . sig))
Now consider the closed terms: these are the inhabitants of Tm Void. You should be able to embed the closed terms into terms with arbitrary free variables. How?
fmap absurd :: Tm Void -> Tm a
The catch, of course, is that this function will traverse the term doing precisely nothing. But it's a touch more honest than unsafeCoerce. And that's why vacuous was added to Data.Void...
Or write an evaluator. Here are values with free variables in b.
data Val b
= b :$$ [Val b] -- a stuck application
| forall a. LV (a -> Val b) (Tm (Maybe a)) -- we have an incomplete environment
I've just represented lambdas as closures. The evaluator is parametrized by an environment mapping free variables in a to values over b.
eval :: (a -> Val b) -> Tm a -> Val b
eval g (Var a) = g a
eval g (f :$ s) = eval g f $$ eval g s where
(b :$$ vs) $$ v = b :$$ (vs ++ [v]) -- stuck application gets longer
LV g t $$ v = eval (maybe v g) t -- an applied lambda gets unstuck
eval g (Lam t) = LV g t
You guessed it. To evaluate a closed term at any target
eval absurd :: Tm Void -> Val b
More generally, Void is seldom used on its own, but is handy when you want to instantiate a type parameter in a way which indicates some sort of impossibility (e.g., here, using a free variable in a closed term). Often these parametrized types come with higher-order functions lifting operations on the parameters to operations on the whole type (e.g., here, fmap, >>=, eval). So you pass absurd as the general-purpose operation on Void.
For another example, imagine using Either e v to capture computations which hopefully give you a v but might raise an exception of type e. You might use this approach to document risk of bad behaviour uniformly. For perfectly well behaved computations in this setting, take e to be Void, then use
either absurd id :: Either Void v -> v
to run safely or
either absurd Right :: Either Void v -> Either e v
to embed safe components in an unsafe world.
Oh, and one last hurrah, handling a "can't happen". It shows up in the generic zipper construction, everywhere that the cursor can't be.
class Differentiable f where
type D f :: * -> * -- an f with a hole
plug :: (D f x, x) -> f x -- plugging a child in the hole
newtype K a x = K a -- no children, just a label
newtype I x = I x -- one child
data (f :+: g) x = L (f x) -- choice
| R (g x)
data (f :*: g) x = f x :&: g x -- pairing
instance Differentiable (K a) where
type D (K a) = K Void -- no children, so no way to make a hole
plug (K v, x) = absurd v -- can't reinvent the label, so deny the hole!
I decided not to delete the rest, even though it's not exactly relevant.
instance Differentiable I where
type D I = K ()
plug (K (), x) = I x
instance (Differentiable f, Differentiable g) => Differentiable (f :+: g) where
type D (f :+: g) = D f :+: D g
plug (L df, x) = L (plug (df, x))
plug (R dg, x) = R (plug (dg, x))
instance (Differentiable f, Differentiable g) => Differentiable (f :*: g) where
type D (f :*: g) = (D f :*: g) :+: (f :*: D g)
plug (L (df :&: g), x) = plug (df, x) :&: g
plug (R (f :&: dg), x) = f :&: plug (dg, x)
Actually, maybe it is relevant. If you're feeling adventurous, this unfinished article shows how to use Void to compress the representation of terms with free variables
data Term f x = Var x | Con (f (Term f x)) -- the Free monad, yet again
in any syntax generated freely from a Differentiable and Traversable functor f. We use Term f Void to represent regions with no free variables, and [D f (Term f Void)] to represent tubes tunnelling through regions with no free variables either to an isolated free variable, or to a junction in the paths to two or more free variables. Must finish that article sometime.
For a type with no values (or at least, none worth speaking of in polite company), Void is remarkably useful. And absurd is how you use it.
I'm thinking that perhaps it's useful in some cases as a type-safe way of exhaustively handling "can't happen" cases
This is precisely right.
You could say that absurd is no more useful than const (error "Impossible"). However, it is type restricted, so that its only input can be something of type Void, a data type which is intentionally left uninhabited. This means that there is no actual value that you can pass to absurd. If you ever end up in a branch of code where the type checker thinks that you have access to something of type Void, then, well, you are in an absurd situation. So you just use absurd to basically mark that this branch of code should never be reached.
"Ex falso quodlibet" literally means "from [a] false [proposition], anything follows". So when you find that you are holding a piece of data whose type is Void, you know you have false evidence in your hands. You can therefore fill any hole you want (via absurd), because from a false proposition, anything follows.
I wrote a blog post about the ideas behind Conduit which has an example of using absurd.
http://unknownparallel.wordpress.com/2012/07/30/pipes-to-conduits-part-6-leftovers/#running-a-pipeline
Generally, you can use it to avoid apparently-partial pattern matches. For example, grabbing an approximation of the data type declarations from this answer:
data RuleSet a = Known !a | Unknown String
data GoRuleChoices = Japanese | Chinese
type LinesOfActionChoices = Void
type GoRuleSet = RuleSet GoRuleChoices
type LinesOfActionRuleSet = RuleSet LinesOfActionChoices
Then you could use absurd like this, for example:
handleLOARules :: (String -> a) -> LinesOfActionsRuleSet -> a
handleLOARules f r = case r of
Known a -> absurd a
Unknown s -> f s
There are different ways how to represent the empty data type. One is an empty algebraic data type. Another way is to make it an alias for ∀α.α or
type Void' = forall a . a
in Haskell - this is how we can encode it in System F (see Chapter 11 of Proofs and Types). These two descriptions are of course isomorphic and the isomorphism is witnessed by \x -> x :: (forall a.a) -> Void and by absurd :: Void -> a.
In some cases, we prefer the explicit variant, usually if the empty data type appears in an argument of an function, or in a more complex data type, such as in Data.Conduit:
type Sink i m r = Pipe i i Void () m r
In some cases, we prefer the polymorphic variant, usually the empty data type is involved in the return type of a function.
absurd arises when we're converting between these two representations.
For example, callcc :: ((a -> m b) -> m a) -> m a uses (implicit) forall b. It could be as well of type ((a -> m Void) -> m a) -> m a, because a call to the contination doesn't actually return, it transfers control to another point. If we wanted to work with continuations, we could define
type Continuation r a = a -> Cont r Void
(We could use type Continuation' r a = forall b . a -> Cont r b but that'd require rank 2 types.) And then, vacuousM converts this Cont r Void into Cont r b.
(Also note that you can use haskellers.com to search for usage (reverse dependencies) of a certain package, like to see who and how uses the void package.)
In dependently-typed languages like Idris, it's probably more useful than in Haskell. Typically, in a total function when you pattern match a value that actually cannot be shoved into the function, you would then construct a value of uninhabited type and use absurd to finalize the case definition.
For example this function removes an element from a list with the type-level costraint that it's present there:
shrink : (xs : Vect (S n) a) -> Elem x xs -> Vect n a
shrink (x :: ys) Here = ys
shrink (y :: []) (There p) = absurd p
shrink (y :: (x :: xs)) (There p) = y :: shrink (x :: xs) p
Where the second case is saying that there is an certain element in an empty list, which is, well absurd. In general, however, the compiler does not know this and we often have to be explicit. Then the compiler can check that the function definition is not partial and we obtain stronger compile-time guarantees.
Through Curry-Howard point of view, where are propositions, then absurd is sort of the QED in a proof by contradiction.
Related
I admit, that my question may stem from a lack of knowledge and be rather vague.
But I try to understand, have some doubts and can't resolve them.
So GHC.Base have such definition, and what is the sense in it:
instance Functor ((->) r) where
fmap = (.)
From the viewpoint of programming language:
We have really base construction (->), I think more base than anything, but maybe terms, and you describe it as a part of very derivative construction (instance Functor). What is the sense? (->) is (->). Functor have any sense as far as (->) described under Haskell hood meaningfully. But not vice versa: (->) have sense while Functor described in Haskell libraries correctly.
From the viewpoint of lambda calculus:
2.1 If from "common sense" definition "(->) r" is a container around r (let's call it "Any_f"), then how function fmap shoul work?
fmap should change value into container, but do not change container-structure, try to write it.
fmap f (Any_f x) <=> Any_f (f x)
(yes, this is non-typed lambda calculus)
2.2. But let's look how Functor ((->) r) defined in Haskell:
instance Functor ((->) r) where
fmap = (.)
-- Or in other words (quotation marks intentionaly):
-- fmap f (Any_f x) = f (Any_f x)
-- fmap :: forall a, b, c => (b -> c) -> (a -> b) -> (a -> c)
So:
"common sense" (not change container structure) tells us to write:
fmap f (Any_f_as_container x) = Any_f_as_container (f x)
types requirements tell us to write:
fmap f (any_f_as_container x) = f (Any_f_as_container x)
Doesn't this means that "instance Functor ((->) r)" is meaningless? And if not - what sense does it has when it changes outermost function (container itself, not container value)?
I will try to convince you that fmap = (.) really is a thing that leaves a container's shape the same, but applies a function to all the elements in the container. But before we do that for (->), let's do it for some simpler types. Specifically, let's do it for types that are containers with a specific number of elements -- i.e., a container with exactly two elements will be TwoF, while one with no elements will be ZeroF. Like this:
data ZeroF a = ZeroF
data OneF a = OneF a
data TwoF a = TwoF a a
data ThreeF a = ThreeF a a a
What should the Functor instances for these look like? Well, the one for OneF looks exactly like in your question:
instance Functor OneF where
fmap f (OneF x) = OneF (f x)
The other ones look pretty similar -- just applying f more (or fewer) times to account for the fact that there are more (or fewer) elements. Here they all are, with some creative whitespace to highlight the similarities/pattern:
instance Functor ZeroF where fmap f (ZeroF ) = ZeroF
instance Functor OneF where fmap f (OneF x0 ) = OneF (f x0)
instance Functor TwoF where fmap f (TwoF x0 x1 ) = TwoF (f x0) (f x1)
instance Functor ThreeF where fmap f (ThreeF x0 x1 x2) = ThreeF (f x0) (f x1) (f x2)
Hopefully for now you agree that this definitely has the flavor of Functor instance that you described in your question: keep the shape of the container the same, and apply the given function f to each element contained within.
So those are containers with a given number of elements. Now, let's write accessors for these containers -- i.e. we want the equivalent of (!!) for lists, where given a number, we pull out that field from the container. Since there's zero elements in a ZeroF, we'll need an indexing type with zero values; while for ThreeF we need an indexing type with three values.
data Zero
data One = One0
data Two = Two0 | Two1
data Three = Three0 | Three1 | Three2
The indexing functions have types that look like this:
indexZero :: ZeroF a -> Zero -> a
indexOne :: OneF a -> One -> a
indexTwo :: TwoF a -> Two -> a
indexThree :: ThreeF a -> Three -> a
I won't implement them all -- they're pretty straightforward -- but here's one to give you the idea in case it's not immediately obvious.
indexTwo (TwoF x0 x1) Two0 = x0
indexTwo (TwoF x0 x1) Two1 = x1
It turns out that the indexing functions have an inverse -- if you give me a function which, when given an index, produces a value, then I can give you a container with those values in it. The types look like this:
tabulateZero :: (Zero -> a) -> ZeroF a
tabulateOne :: (One -> a) -> OneF a
tabulateTwo :: (Two -> a) -> TwoF a
tabulateThree :: (Three -> a) -> ThreeF a
(Do you see why this is the right type for an inverse? Note that, say, TwoF a -> Two -> a is the same type as TwoF a -> (Two -> a)!) Just to give you an idea of how these are implemented, in case it's not immediately obvious, we simply apply the indexing function to each index:
tabulateZero ix = ZeroF
tabulateOne ix = OneF (ix One0 )
tabulateTwo ix = TwoF (ix Two0 ) (ix Two1 )
tabulateThree ix = ThreeF (ix Three0) (ix Three1) (ix Three2)
It's not too hard to prove that tabulateX . indexX = id and indexX . tabulateX = id for each X, i.e. that tabulation really is the inverse of indexing.
Okay, but hold up now and take a look at what we've just done: we have turned a function (like Two -> a) into a container (like TwoF a), and vice versa. The types Two -> a and TwoF a are, morally speaking, exactly the same thing. So it seems reasonable to think we could implement fmap for Two -> a -- for example, just by converting to TwoF a and back as appropriate!
twomap :: (a -> b) -> (Two -> a) -> (Two -> b)
twomap f = indexTwo . fmap f . tabulateTwo
Let's visualize what that's doing. We'll start with an arbitrary indexing function:
\case Two0 -> x0; Two1 -> x1
Now we go through the process:
\case Two0 -> x0; Two1 -> x1
tabulateTwo
TwoF x0 x1
fmap f
TwoF (f x0) (f x1)
indexTwo
\case Two0 -> f x0; Two1 -> f x1
Since f gets applied in both branches, we could pull that out of the case:
f . (\case Two0 -> x0; Two1 -> x1)
That second term is exactly the indexing function we started out with. In other words, we have just determined another, simpler implementation for twomap:
twomap f ix = f . ix
If you work through similar reasoning for zeromap, onemap, and threemap, you'll discover they actually all have that same implementation! We can do this uniformly for all the various sizes of container just by going polymorphic; instead of having onemap for changing One -> a's, etc., let's have an xmap for changing x -> a's:
xmap :: (a -> b) -> (x -> a) -> (x -> b)
xmap f ix = f . ix
Of course, we don't have to name f and ix:
xmap = (.)
...and this is the Functor instance for (x -> _).
(->) isn't just syntax. It's an operator like any other, but at the type level instead of the term level. It has a kind Type -> Type -> Type, which means if you apply it to a single type, you get back not a type, but another "function" of kind Type -> Type.
Type -> Type is the kind of all functors, so it's reasonable to think the partially applied (->) operator might be a functor as well, which is what
instance Functor ((->) r) where
fmap = (.)
defines. That is, mapping a function over another function means to compose the two functions.
As a "container", think of a function (something of type r -> a) as containing all possible values of type a that you can get by applying the function to an argument of type r. fmap will apply a function to whatever the other function returns. (Or in theory, apply it to every value that the other could return.)
So the answer is: functions can be represent either as (a -> b) or as Map a b - for function with finite count of possible arguments these are literally two equivalent representations.
So instance Functor (Map r) is meaningful and it would be implemented just as instance Functor ((->) r) implemented already.
And the answer above is confirmed by the implementation of instance Functor ((,) r). Yes this is a bit different than Map r, but as close as possible.
P.S.
#chepner : I can't mark your answer as "best answer" because I don't understand (and almost don't agree) with one word in one sentense:
(->) isn't just syntax. It's an operator like any other
Function is not "like any other" operation (I used notion "construction") function is magical- or under-hood-compiler- construction, on which all other fuctions are based.
I need to write the Functor instances for the Flip datatype:
data K a b = K a
newtype Flip f a b = Flip (f b a) deriving (Eq, Show)
instance Functor (Flip K a) where
fmap=undefined
The solution I was given in class is:
instance Functor (Flip K a) where
fmap f (Flip (K b)) = Flip (K (f b))
I really don't understand what's going on here and I'm beginning to doubt my whole understanding of data types and functors. What I do understand is this (please correct me if any of this is wrong):
K is a data type that turns 2 parameters into a structure K a ( that only keeps the first parameter)
Flip is a datatype that turns 3 arguments into a structure with one
Because in fmap :: (a-> b) -> f a -> f b, f a has kind *, to write the Functor instance of Flip, we write it on the last type in Flip. Aka f and a are "constants" in a way, and we write the functor for the type b. I would write something like:
instance Functor (Flip f a) where
fmap f (Flip x y z) = fmap Flip x y (f z)
I know that that is completely wrong but I'm not sure why.
Also, why would we bring K into the Functor instance of Flip? Can someone explain thoroughly the process of coming up with this solution and why it is correct?
K is a data type that turns 2 parameters into a structure K a ( that only keeps the first parameter)
This isn't quite right. K a b is a data type formed using two parameters, but it's not really right to say that it "turns them into" anything. Instead, it's simply just stating to the world that there now exists a new type: K a b. "So what?" you might ask. Well, the second half of the data type defines how to make new values of this type. That part says, "You can make a new value of type K a b with this function I'll call K which has type a -> K a b." It's really important to recognize that there is a distinction between the type K and the constructor K.
So, it's not that K "only keeps the first parameter"—it's that the constructor K (which is a function) happens to not take any arguments of type b.
Flip is a datatype that turns 3 arguments into a structure with one
Just as above, this is not quite right. The Flip declaration states that there can be values of type Flip f a b, and the only way to make them is by using the constructor Flip that has type f b a -> Flip f a b.
In case you're wondering how I'm coming up with the type signatures for the constructors K and Flip, it's not actually mysterious, and you can double check by typing :t K or :t Flip into GHCi. These types are assigned based entirely on the right hand side of the data type declaration. Also, note that the type name and constructor don't have to be the same. For instance, consider this data type:
data Foo a = Bar Int a | Foo String | Baz a a
This declares a type Foo a with three constructors:
Bar :: Int -> a -> Foo a
Foo :: String -> Foo a
Baz :: a -> a -> Foo a
Basically, each of the types after the constructor name are the arguments, in order, to the constructor.
Because in fmap :: (a-> b) -> f a -> f b, f a has kind *, to write the Functor instance of Flip, we write it on the last type in Flip. Aka f and a are "constants" in a way, and we write the functor for the type b.
This is basically right! You could also say that f has kind * -> *. Since Flip has kind (* -> *) -> * -> * -> *, you need to provide it two type arguments (the first of kind * -> * and the second of kind *) to get it to the right kind. Those first two arguments become fixed ("constants" in a way) in the instance.
I would write something like: ... I know that that is completely wrong but I'm not sure why.
The reason your instance is completely wrong is that you've mixed up the type with the constructor. It doesn't make sense to put (Flip x y z) in the pattern position where you did because the constructor Flip only takes one argument—remember, it's type is Flip :: f b a -> Flip f a b! So you'd want to write something like:
instance Functor (Flip f a) where
fmap f (Flip fxa) = ...
Now, what do you fill in for the ...? You have a value fxa :: f x a, and you have a function f :: x -> y, and you need to produce a value of type f y a. Honestly, I don't know how to do that. After all, what is a value of typ f x a? We don't know what f is?!
Also, why would we bring K into the Functor instance of Flip? Can someone explain thoroughly the process of coming up with this solution and why it is correct?
We saw just above that we can't write the Functor instance for an arbitrary f, but what we can do is write it for a particular f. It turns out that K is just such a particular f that works. Let's try to make it work:
instance Functor (Flip K a) where
fmap f (Flip kxa) = ...
When f was arbitrary, we got stuck here, but now we know that kxa :: K x a. Remember that the only way to make a value of type K x a is using the constructor K. Therefore, this value kxa must have been made using that constructor, so we can break it apart as in: kxa ⩳ K x' where x' :: x. Let's go ahead and put that into our pattern:
fmap f (Flip (K x')) = ...
Now we can make progress! We need to produce a value of type Flip K a y. Hmm. The only way to produce a value of type Flip is using the Flip constructor, so let's start with that:
fmap f (Flip (K x')) = Flip ...
The Flip constructor at type Flip K a y takes a value of type K y a. The only way to produce one of those is with the K constructor, so let's add that:
fmap f (Flip (K x')) = Flip (K ...)
The K constructor at type K y a takes a value of type y, so we need to provide a value of type y here. We have a value x' :: x and a function f :: x -> y. Plugging the first into the second gives us the value we need:
fmap f (Flip (K x')) = Flip (K (f x'))
Just rename x' to b, and you have exactly the code your teacher provided.
DDub wrote in their answer:
You have a value fxa :: f x a, and you have a function f :: x -> y, and you need to produce a value of type f y a. Honestly, I don't know how to do that. After all, what is a value of type f x a? We don't know what f is?!
And I agree, but I woulld like to add a bit. Your teacher's idea as to how to deal with this is pretty cool (things like this K come in quite handy when you are trying to write down some counterexample, like here), and yet, I reckon we can make this code way broader. I use Data.Bifunctor.
So, what are Bifunctors? They are just what their name says: a * -> * -> * type (which we call bifunctors as well sometimes, yet they are not the same thing) which allows mapping over its both arguments (snippet from the source):
class Bifunctor p where
-- | Map over both arguments at the same time.
--
-- #'bimap' f g ≡ 'first' f '.' 'second' g#
bimap :: (a -> b) -> (c -> d) -> p a c -> p b d
bimap f g = first f . second g
{-# INLINE bimap #-}
-- | Map covariantly over the first argument.
--
-- #'first' f ≡ 'bimap' f 'id'#
first :: (a -> b) -> p a c -> p b c
first f = bimap f id
{-# INLINE first #-}
-- | Map covariantly over the second argument.
--
-- #'second' ≡ 'bimap' 'id'#
second :: (b -> c) -> p a b -> p a c
second = bimap id
{-# INLINE second #-}
So, here is how I would go about that:
instance Bifunctor f => Functor (Flip f a) where
fmap x2y (Flip fxa) = Flip (first x2y fxa)
Speaking of your teacher's code, it's a very nice idea, yet a more narrow one as K is a Bifunctor:
instance Bifunctor K where
bimap f _g (K a) = K (f a)
A lawful one:
bimap id id (K a) = K (id a) = id (K a)
As it says in the link above, having bimap only written down, that's the only law we need to worry about.
We just need to use sane and helpful naming, and suddenly it all becomes simple and clear (as opposed to torturous and contorted):
data K b a = MkK b -- the type (K b a) "is" just (b)
newtype Flip f a b = MkFlip (f b a) -- the type (Flip f a b) "is" (f b a)
deriving (Eq, Show)
instance Functor (Flip K a) where
-- fmap :: (b -> c) -> Flip K a b -> Flip K a c
fmap g (MkFlip (MkK b)) = MkFlip (MkK (g b))
-- MkK b :: K b a
-- MkFlip (_ :: K b a) :: Flip K a b
There's not even one question arising in our minds now looking at this, not one doubt we aren't able to immediately resolve.
Using same names for types and for data constructors while teaching, as well as using f both for "f"unction and "f"unctor, is pure abuse of the students.
Only when you've become fed up with all the Mks and don't feel they are helpful to you in any way, you can safely and easily throw them away, as experts usually do.
From functors that are not applicatives:
A type constructor which is a Functor but not an Applicative. A simple example is a pair:
instance Functor ((,) r) where
fmap f (x,y) = (x, f y)
But there is no way how to define its Applicative instance without imposing additional restrictions on r. In particular, there is no way how to define pure :: a -> (r, a) for an arbitrary r.
Question 1: Why is this so? Here is how pure could work with functions f of type a -> b:
(pure f) (pure x, pure y) = (pure x, pure f y)
From there, the definition of pure :: a -> (r, a) could depend on what r is. For example, if r is Integer, then you could define
pure x = (0 :: Integer, x)
in your instance declaration. So what is the issue?
Question 2: Can we say in general that if F is a functor, then <*> can always be defined, but pure might not always be defined?
Suppose we have
pure :: forall r a. a -> (r, a)
then, in particular, we have
magic :: forall r. r
magic = fst (pure ())
Now, we can specialise the type variable r to get
magic :: Void
where Void is the datatype with no constructors, which means
magic = undefined
but as type variables (and the types which specialise them) play no run time role, that means magic is always undefined.
We've discovered that ((,) r) can be Applicative only for inhabited r. And there's more. With any such instance, we can write
munge :: r -> r -> r
munge r0 r1 = fst ( pure (\ _ _ -> ()) <*> (r0, ()) <*> (r1, ()) )
to define a binary operator on r. The Applicative laws tell us effectively that munge must be an associative operator that absorbs magic on either side.
That's to say there is a sensible instance
instance Monoid r => Applicative ((,) r) where
pure a = (mempty, a)
(r0, f) <*> (r1, s) = (mappend r0 r1, f s)
(exactly what you get when you take pure=return; (<*>)=ap from the Monad (Writer r)).
Of course, some pedants would argue that it is legal (if unhelpful) to define
instance Monoid r where
mempty = undefined
mappend _ _ = undefined
-- Monoid laws clearly hold
but I would argue that any sensible type class instance should contribute nontrivially to the defined fragment of the language.
Answer 1:
(pure f) (pure x, pure y) = (pure x, pure f y)
I don't understand what you mean by this line. It looks like nonsense: pure f would be a pair, and you can't apply a pair as if it were a function.
From there, the definition of pure :: a -> (r, a) could depend on what r is.
That is exactly the problem. r is fully general; the instance declaration says ((,) r) is a Functor for all types r. That means you have to somehow implement a single pure :: a -> (r, a) that works with any type r that a caller might choose. This is impossible because there is no way to conjure up an arbitrary r from thin air.
Or as your quote says:
In particular, there is no way how to define pure :: a -> (r, a) for an arbitrary r.
If you try to do something like
pure x = (0 :: Integer, x)
you get an error:
Couldn't match expected type ‘r’ with actual type ‘Integer’
‘r’ is a rigid type variable bound by
the instance declaration
at ...
Answer 2:
What would <*> look like for pairs? It would be a function like
(<*>) :: (r, a -> b) -> (r, a) -> (r, b)
(r1, f) (r2, x) = (???, f x)
But what do you do with the ??? part? You have to put a value of r there, and fortunately you have some of those available (r1, r2). The problem is that (for arbitrary r) there is no general way to combine two values, so you have to pick one of them.
That's where you run into trouble with the laws:
pure id <*> v = v
This law says we have to pick r2 to preserve v.
u <*> pure y = pure ($ y) <*> u
Since we have to pick r2 in <*>, the right-hand side of this law says the result will contain the r part of u. But that clashes with the left-hand side, which says that we get whatever r was returned by pure y. (u is a completely arbitrary pair so there's no way a fixed value returned by pure is always going to match it.)
So we have a contradiction, meaning we can't even define <*> for ((,) r). Therefore the answer to your second question is "no".
That said, there is a standard Applicative instance for pairs but it requires r to be a Monoid:
instance (Monoid r) => Applicative ((,) r) where
pure x = (mempty, x)
(r1, f) (r2, x) = (mappend r1 r2, f x)
In Haskell, there are many examples of higher kinded polymorphism when dealing with ad hoc polymorphism, such as Monad and Functor. However, I cannot think of any examples of this for parametric polymorphism.
Is this possible, and if so, can I have an example of one which is useful?
If you still allow typeclass constraints, then the answer is, sure! E.g. I'd still call something like
normalise :: (Foldable f, Functor f, Fractional n) => f n -> f n
normalise v = fmap (/sum v) V
parametric polymorphism. But I suppose that's not what you have in mind.
Another thing that's obviously possible is to just contrain types to have a particular form _ _, like
hmap :: (f a -> f b) -> [f a] -> [f b]
hmap = map
This isn't exactly remarkable, but it could possibly be useful in some applications as a subtle hint to the type checker. In fact, this is one way you can solve the phantom argument problem: instead of
class LengthyList l where minimumLength :: l a -> Int
instance LengthyList [] where minimumLength _ = 0
instance LengthyList NonEmpty where minimumLength _ = 1
you might make the signature
minimumLength :: p (l a) -> Int
aka
minimumLength :: proxy (l a) -> Int
Thereby you still pass in the type-information of l, but guarantee that the implementation cannot try to evaluate the argument at runtime.
The standard way to do this is however
minimumLength :: Tagged (l a) Int
or
minimumLength :: Proxy (l a) -> Int
Generally though, there's nothing you could do with f a that couldn't also be done with fa, so essentially you could rewrite the type of any such higher-order parametric function to a first-order parametrically polymorphic one.
You totally can do this. A type synonym pigworker is fond of:
type f ~> g = forall a . f a -> g a
This, for reasons I don't actually know, represents a natural transformation (whatever exactly that is) between functors f and g. But a function can take an argument of type f ~> g and apply it to as many types f a as it likes. Using non-regular types (specifically, higher-order nested data types, as Ralf Hinze, for example, explored in Numerical Representations as Higher-Order Nested Datatypes), it could be applied to an unbounded number of different types.
A contrived example:
{-# LANGUAGE RankNTypes, TypeOperators #-}
type f ~> g = forall a . f a -> g a
data Two g a = Two (g a) (g a)
data Foo f a = This (f a)
| That (Foo (Two f) a)
hello :: (f ~> g) -> Foo f a -> Foo g a
hello t (This fa) = This (t fa)
hello t (That buh) =
That (hello (\(Two x y) -> Two (t x) (t y)) buh)
hello is polymorphic in the types f and g, each of which has kind * -> *. † I believe that converting this to use only types of kind * could require non-trivial refactoring.
†In fact, if you enable PolyKinds, f and g will each have a polykinded type k -> *.
One example I'm quite fond of is the foldr operator for lists indexed by their length: it is parametrically polymorphic over a predicate p of kind Nat -> * and guarantees that if you apply it to a list of length m then you get back a proof of p m.
This corresponds to this type:
foldr :: forall a (p :: Nat -> *).
(forall n. a -> p n -> p ('Succ n)) ->
p 'Zero ->
forall n. Vec a n -> p n
This extra precision makes it possible to implement e.g. append using foldr rather than having to proceed by pattern-matching.
append :: forall a m n. Vec a m -> Vec a n -> Vec a (m :+: n)
I've uploaded a complete gist with all the right language extensions turned on and the code corresponding to these types in case you want to peek.
In my free time I'm learning Haskell, so this is a beginner question.
In my readings I came across an example illustrating how Either a is made an instance of Functor:
instance Functor (Either a) where
fmap f (Right x) = Right (f x)
fmap f (Left x) = Left x
Now, I'm trying to understand why the implementation maps in the case of a Right value constructor, but doesn't in the case of a Left?
Here is my understanding:
First let me rewrite the above instance as
instance Functor (Either a) where
fmap g (Right x) = Right (g x)
fmap g (Left x) = Left x
Now:
I know that fmap :: (c -> d) -> f c -> f d
if we substitute f with Either a we get fmap :: (c -> d) -> Either a c -> Either a d
the type of Right (g x) is Either a (g x), and the type of g x is d, so we have that the type of Right (g x) is Either a d, which is what we expect from fmap (see 2. above)
now, if we look at Left (g x) we can use the same reasoning to say that its type is Either (g x) b, that is Either d b, which is not what we expect from fmap (see 2. above): the d should be the second parameter, not the first! So we can't map over Left.
Is my reasoning correct?
This is right. There is also another quite important reason for this behavior: You can think of Either a b as a computation, that may succeed and return b or fail with an error message a. (This is also, how the monad instance works). So it's only natural, that the functor instance won't touch the Left values, since you want to map over the computation, if it fails, there's nothing to manipulate.
Your account is right of course. Maybe the reason why we have a difficulty with instances like this is that we are really defining infinitely many functor instances at once -- one for each possible Left type. But a Functor instance is a systematic way of operating on the infinitely many types in the system. So we are defining infinitely many ways of systematically operating on the infinitely many types in the system. The instance involves generality in two ways.
If you take it by stages, though, maybe it's not so strange. The first of these types is a longwinded version of Maybe using the unit type () and its only legitimate value ():
data MightBe b = Nope () | Yep b
data UnlessError b = Bad String | Good b
data ElseInt b = Else Int | Value b
Here we might get tired and make an abstraction:
data Unless a b = Mere a | Genuine b
Now we make our Functor instances, unproblematically, the first looking a lot like the instance for Maybe:
instance Functor MightBe where
fmap f (Nope ()) = Nope () -- compare with Nothing
fmap f (Yep x) = Yep (f x) -- compare with Just (f x)
instance Functor UnlessError where
fmap f (Bad str) = Bad str -- a more informative Nothing
fmap f (Good x) = Good (f x)
instance Functor ElseInt where
fmap f (Else n) = Else n
fmap f (Value b) = Value (f b)
But, again, why bother, let's make the abstraction:
instance Functor (Unless a) where
fmap f (Mere a) = Mere a
fmap f (Genuine x) = Genuine (f x)
The Mere a terms aren't touched, as the (), String and Int values weren't touched.
As others mentioned, Either type is a functor in its both arguments. But in Haskell we are able to (directly) define only functors in a type's last arguments. In cases like this, we can get around the limitation by using newtypes:
newtype FlipEither b a = FlipEither { unFlipEither :: Either a b }
So we have constructor FlipEither :: Either a b -> FlipEither b a that wraps an Either into our newtype with swapped type arguments. And we have dectructor unFlipEither :: FlipEither b a -> Either a b that unwraps it back. Now we can define a functor instance in FlipEither's last argument, which is actually Either's first argument:
instance Functor (FlipEither b) where
fmap f (FlipEither (Left x)) = FlipEither (Left (f x))
fmap f (FlipEither (Right x)) = FlipEither (Right x)
Notice that if we forget FlipEither for a while we get just the definition of Functor for Either, just with Left/Right swapped. And now, whenever we need a Functor instance in Either's first type argument, we can wrap the value into FlipEither and unwrap it afterward. For example:
fmapE2 :: (a -> b) -> Either a c -> Either b c
fmapE2 f = unFlipEither . fmap f . FlipEither
Update: Have a look at Data.Bifunctor, of which Either and (,) are instances of. Each bifunctor has two arguments and is a functor in each of them. This is reflected in Bifunctor's methods first and second.
The definition of Bifunctor of Either is very symetric:
instance Bifunctor Either where
bimap f _ (Left a) = Left (f a)
bimap _ g (Right b) = Right (g b)
first f = bimap f id
second f = bimap id f
Now, I'm trying to understand why the
implementation maps in the case of a
Right value constructor, but doesn't
in the case of a Left?
Plug in here and it might make sense.
Assume a = String (an error message)
You apply Either a to an Float.
So you have an f: Float -> Integer say for example roundoff.
(Either String) (Float) = Either String Float.
now (fmap f):: Either String Float -> Either String Int
So what are you going to do with f? f doesn't have a clue what to do with strings so you can't do anything there. That is obviously the only thing you can act on are the right values while leaving the left values unchanged.
In other words Either a is a functor because there is such an obvious fmap given by:
for Right values apply f
for Left values do nothing