How does the Reader monad's "ask" function work? - haskell

data T b = E | N b (T b) (T b)
f :: T b -> Reader Int (T Int)
f (N i l r) = ask >>= \x -> local ((-)4) (f l) >>= \l' -> local ((-)1) (f r) >>= \r' -> return (N x l' r')
f E = return E
I have a problem with understanding how this code works. Especially, how does ask know where the environment is (in our case just Int)?
To be more precise: I am an imperative programmer and in such languages it is easy. Methods can be called on any object like: obj.f(), or we have to pass data by argument when we want function use external data.

That's kind of what the Reader monad does; it gives you an ask function, which "magically" pops up a value out of thin air. To actually use this, you need to call runReader, and give it the Int environment. The Reader type then automatically propagates that from the runReader call to each of the ask calls.

Short, hand-wavy answer. The Reader Int (T Int) value is essentially just a wrapped-up function of type Int -> (T Int). In order to run that function, we first need to extract it. We do that with runReader.
data T b = ... deriving (Show)
main = let tree = (N 10 (N 8 E E) E)
g = f tree
h = runReader g
in print $ h 20
(Typically, you would simply write print $ runReader (f tree) 20; I split it up to correspond to the sketchy analogy below.)
ask (defined by the MonadReader typeclass and as implemented by the ReaderT monad transformer used to define the Reader type) essentially retrieves the value of the argument passed to h.
In some sense, the Reader Int (T Int) is an object that contains a function g that calls a function ask. runReader g creates a new function which, when called, defines a function ask that simply returns its argument, then calls g. Now when g calls ask, it gets back the argument originally passed to h.

I recomend reading this first. Ask is defined:
ask :: (Monad m) => ReaderT r m r
ask = ReaderT return
and reader:
newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }
type Reader r = ReaderT r Identity
so
do
r <- ask
...
is equivalent to
do
r <- ReaderT return
...
So essentially <- just reaches into the identity monad, and grabs what ever value that will eventually be lifted by runReader R = return.
This enables global variables in haskell.

Related

What's the use case for the MonadReader instance for (->) r

I find the MonadReader instance for (->) r difficult to understand.
Someone from irc mentions one use case for extending some polymorphic functions found in other people's package. I couldn't recall exactly what he meant. Here's an example that relates to what he said but I don't see the point. Could anyone give another example on the usecase of MonadReader for (->) r
func :: (Show a, MonadReader Int m) => Bool -> m a
func b = case b of
True -> do
i <- ask
show i
False -> "error"
main :: IO ()
main = print $ func True 5
The point is to make it easier to combine functions that all take the same environment.
Consider the type a -> Env -> b, where Env is some data type that contains all your "global" variables. Let's say you wanted to compose two such functions. You can't just write h = f2 . f1, because f1's return type Env -> b doesn't match f2's argument type b.
f1 :: a -> Env -> b -- a -> ((->) Env b)
f2 :: b -> Env -> c -- b -> ((->) Env c)
h :: a -> Env -> c
h x e = let v = f1 x e
in f2 v e
Because there is an applicable MonadReader instance for the monad (->) Env, you can write this as
-- The class, ignoring default method implementations, is
-- class Monad m => MonadReader r m | m -> r where
-- ask :: m r
-- local :: (r -> r) -> m a -> m a
-- reader :: (r -> a) -> m a
--
-- The functional dependency means that if you try to use (->) Env
-- as the monad, Env is forced to be the type bound to r.
--
-- instance MonadReader r ((->) r) where
-- ask = id
-- local f m = m . f
-- reader = id
h :: MonadReader Env m => a -> m c
h x = do
v <- f1 x
f2 v
-- h x = f1 x >>= f2
without explicit reference to the environment, which h doesn't
care about; only f1 and f2 do.
More simply, you can use the Kleisli composition operator to define the same function.
import Control.Monad
h :: MonadReader Env m => a -> m c
h = f1 >=> f2
In your example, ask is simply how you get access to the environment from inside the body of the function, rather than having it as a preexisting argument to the function. Without the MonadReader instance, you would write something like
func :: Show a => Bool -> Int -> a -- m ~ (->) Int
func b i = case b of
True -> show i
False -> error "nope"
The definition of main stays the same. However, (->) Int isn't the only type that has a MonadReader instance; there could be a more complicated monad stack
that you are using elsewhere, which the more general type (Show a, MonadReader Int m) => Bool -> m a allows you to use instead of "just" (->) Int.
I'm not sure it was intended to have a use case separate from the Reader monad.
Here's some of the history...
The inspiration for the transformers library was the set of lecture notes Functional Programming with Overloading and Higher-Order Polymorphism (Mark P. Jones, 1995). In these notes, several named monads (State, Id, List, Maybe, Error, and Writer) were discussed. For example, the Writer monad type and its instance were defined as:
data Writer a = Result String a
instance Monad Writer where
result x = Result "" x
Result s x ‘bind‘ f = Result (s ++ s’) y
where Result s’ y = f x
The reader monad was also discussed, but it wasn't defined as a separate type. Rather a Read type alias was used together with a Monad instance defined directly in terms of the partially applied function type (->) r:
type Read r = (r ->)
instance Monad (r->) where
result x = \r -> x
x ‘bind‘ f = \r -> f (x r) r
I don't actually know if these type-level "sections" (r ->) were valid Haskell syntax at the time. Anyway, it's not valid syntax with modern GHC versions, but that's how it appeared in the notes.
The first version of the transformers library authored by Andy Gill -- or at least the first that I was able to find, and it was actually still part of the base library at that time -- was checked into Git in June, 2001. It introduced the MonadReader class and the newtype wrapped Reader:
newtype Reader r a = Reader { runReader :: r -> a }
together with its Functor, Monad, MonadFix, and MonadReader instances. (No Applicative -- that hadn't been invented yet.) It also included a set of instances for (->) r with the comment:
The partially applied function type is a simple reader monad
So, I think the original formulation in the lecture notes led Andy to include these instances for (->) r, even though he also introduced a dedicated Reader newtype for consistency with the other monads in the transformers library.
Anyway, that's the history. As for use cases, I can only think of one serious one, though perhaps it isn't that compelling. The lens library is designed to interface well with MonadState and MonadReader to access complex states/contexts. Because functions like:
view :: MonadReader s m => Getting a s a -> m a
preview :: MonadReader s m => Getting (First a) s a -> m (Maybe a)
review :: MonadReader b m => AReview t b -> m t
are defined in terms of the MonadReader instance, they can be used both in a traditional Reader context:
do ...
outdir <- view (config.directories.output)
...
and in a plain function context:
map (view (links.parent.left)) treeStructure
Again, not necessarily a compelling use case, but it's a use case.

Why to define the constructor parameter of Reader as a function?

When learning the Reader Monad, I find that it is defined as:
newtype Reader r a = Reader { runReader :: r -> a }
instance Monad (Reader r) where
return a = Reader $ \_ -> a
m >>= k = Reader $ \r -> runReader (k (runReader m r)) r
I want to known why using function as constructor parameter instead of something else such as a tuple:
newtype Reader r a = Reader { runReader :: (r, a) }
instance Monad (Reader r) where
-- Here I cannot get r when defining return function,
-- so does that's the reason that must using a function whose input is an "r"?
return a = Reader (r_unknown, a)
m >>= k = Reader (fst $ runReader m) (f (snd $ runReader m))
According to the Reader definition, we need a "environment" which we can use to generate a "value". I think a Reader type should contain the information of "environment" and "value", so the tuple seems perfect.
You didn't mention it in the question, but I guess you thought specifically of using a pair for defining Reader because it also makes sense to think of that as a way of providing a fixed environment. Let's say we have an earlier result in the Reader monad:
return 2 :: Reader Integer Integer
We can use this result to do further calculations with the fixed environment (and the Monad methods guarantee it remains fixed throughout the chain of (>>=)):
GHCi> runReader (return 2 >>= \x -> Reader (\r -> x + r)) 3
5
(If you substitute the definitions of return, (>>=) and runReader in the expression above and simplify it, you will see exactly how it reduces to 2 + 3.)
Now, let's follow your suggestion and define:
newtype Env r a = Env { runEnv :: (r, a) }
If we have an environment of type r and a previous result of type a, we can make an Env r a out of them...
Env (3, 2) :: Env Integer Integer
... and we can also get a new result from that:
GHCi> (\(r, x) -> x + r) . runEnv $ Env (3, 2)
5
The question, then, is whether we can capture this pattern through the Monad interface. The answer is no. While there is a Monad instance for pairs, it does something quite different:
newtype Writer r a = Writer { Writer :: (r, a) }
instance Monoid r => Monad (Writer r) where
return x = (mempty, x)
m >>= f = Writer
. (\(r, x) -> (\(s, y) -> (mappend r s, y)) $ f x)
$ runWriter m
The Monoid constraint is needed so that we can use mempty (which solves the problem that you noticed of having to create a r_unknown out of nowhere) and mappend (which makes it possible to combine the first elements of the pair in a way that doesn't violate the monad laws). This Monad instance, however, does something very different than what the Reader one does. The first element of the pair isn't fixed (it is subject to change, as we mappend other generated values to it) and we don't use it to compute the second element of the pair (in the definition above, y does not depend neither on r nor on s). Writer is a logger; the r values here are output, not input.
There is one way, however, in which your intuition is justified: we can't make a reader-like monad using a pair, but we can make a reader-like comonad. To put it very loosely, Comonad is what you get when you turn the Monad interface upside down:
-- This is slightly different than what you'll find in Control.Comonad,
-- but it boils down to the same thing.
class Comonad w where
extract :: w a -> a -- compare with return
(=>>) :: w a -> (w a -> b) -> w b -- compare with (>>=)
We can give the Env we had abandoned a Comonad instance:
newtype Env r a = Env { runEnv :: (r, a) }
instance Comonad (Env r) where
extract (Env (_, x)) = x
w#(Env (r, _)) =>> f = Env (r, f w)
That allows us to write the 2 + 3 example from the beginning in terms of (=>>):
GHCi> runEnv $ Env (3, 2) =>> ((\(r, x) -> x + r) . runEnv)
(3,5)
One way to see why this works is noting that an a -> Reader r b function (i.e. what you give to Reader's (>>=)) is essentially the same thing that an Env r a -> b one (i.e. what you give to Env's (=>>)):
a -> Reader r b
a -> (r -> b) -- Unwrap the Reader result
r -> (a -> b) -- Flip the function
(r, a) -> b -- Uncurry the function
Env r a -> b -- Wrap the argument pair
As further evidence of that, here is a function that changes one into the other:
GHCi> :t \f -> \w -> (\(r, x) -> runReader (f x) r) $ runEnv w
\f -> \w -> (\(r, x) -> runReader (f x) r) $ runEnv w
:: (t -> Reader r a) -> Env r t -> a
GHCi> -- Or, equivalently:
GHCi> :t \f -> uncurry (flip (runReader . f)) . runEnv
\f -> uncurry (flip (runReader . f)) . runEnv
:: (a -> Reader r c) -> Env r a -> c
To wrap things up, here is a slightly longer example, with Reader and Env versions side-by-side:
GHCi> :{
GHCi| flip runReader 3 $
GHCi| return 2 >>= \x ->
GHCi| Reader (\r -> x ^ r) >>= \y ->
GHCi| Reader (\r -> y - r)
GHCi| :}
5
GHCi> :{
GHCi| extract $
GHCi| Env (3, 2) =>> (\w ->
GHCi| (\(r, x) -> x ^ r) $ runEnv w) =>> (\z ->
GHCi| (\(r, x) -> x - r) $ runEnv z)
GHCi| :}
5
First of all note that your bind function is wrong and would not compile.
If the Reader were defined as you describe with a tuple, there would be problems:
The monad laws would be violated, e.g. left identity, which states that:
return a >>= f == f a
or the right identity:
m >>= return == m
would be broken, depending on the implmentation of >>= because >>= would forget either the first tuple element of the first argument or the second, i.e. if the implmentation would be:
(Reader (mr, mv)) >>= f =
let (Reader (fr, fv)) = f mv
in Reader (mr, fv)
then we would always lose the reader value that comes out of f (aka fr) and otherwise if >>= would be
(Reader (mr, mv)) >>= f =
let (Reader (fr, fv)) = f mv
in Reader (fr, fv)
-- ^^^ tiny difference here ;)
we would always lose mr.
A Reader is some action, that may ask for a constant value, which cannot be changed by another monadic action, which is read-only.
But when defined with a tuple, we could super-easy overwrite the reader value, e.g. whith this function:
tell :: x -> BadReader x ()
tell x = BadReader (x, ())
If a reader is instead defined with a function, this is impossible (try it)
Also, that enviroment is actually not required before converting a Reader to a pure value (aka running the Reader), so from this alone it makes sense to use a function instead of a tuple.
When using a tuple, we would have to provide the Reader value even before we actually run an action.
You can see that in your return definition, you even point out the problem, where the r_unknown comes from ...
To get a btter intuition, let's assume a Reader action that returns the Persons with a certain age from the Addressbook:
data Person = MkPerson {name :: String, age :: Int}
type Addressbook = [Person]
personsWithThisAge :: Int -> Reader Addressbook [Person]
personsWithThisAge a = do
addressbook <- ask
return (filter (\p -> age p == a) addressbook)
This personsWithAge function returns a Reader action and since it only asks for the Addressbook, it is like a function that accepts an addressbook and gives back a [Person] list,
so it is natural to define a reader as just that, a function from some input to a result.
We could rewrite this Reader action to be a function of the Addressbook like this:
personsWithThisAgeFun :: Int -> Addressbook -> [Person]
personsWithThisAgeFun a addressbook =
filter (\p -> age p == a) addressbook
But why invent Reader??
The real value of Reader shows when combining several functions like e.g. personsWithThisAge, that all depend on (the same) one constant Addressbook.
Using a Reader we don't have to explicitly pass some Addressbook around, individual Reader actions don't even have any way at all to modify the Addressbook - Reader guarantees us, that every action uses the same, unmodified Addressbook, and all a Reader action can ever to with the environment is ask for it.
The only way to implement this, with these guarantees is with a function.
Also if you look at the monad instances that are included in the standard library, you will see that (r ->) is a monad; actually it is identical to the Reader monad apart from some technical differences.
Now the structure you describe with the tuple is actually pretty close to a Writer monad, what is write-only , but that's out of scope.

Haskell, parameters of ask

Could you help what parameter is getting by ask ?
We often can see ask >>= f
It means that ask >>= f = (\k -> f (ask k) k)
So ask must be able to get k, function from enviroment.
However, in docs it is written: ask :: m r.
Where am I wrong ?
It's the Reader monad. Ultimately the best answer is just to study its implementation, which in it simplest version (no monad transformers, no classes) can be defined like this:
newtype Reader r a = Reader { runReader :: r -> a }
This is a newtype declaration, so Reader r a is just a "relabeling" (so to speak) of the function type r -> a. ask is defined like this:
ask :: Reader r r
ask = Reader (\r -> r)
Which means that ask is a relabeled identity function—the function that just returns its own argument. We can see this if we use the runReader operation to feed values to it :
ghci> runReader ask 5
5
ghci> runReader ask "Hello world!"
"Hello world!"
That doesn't look very useful, but the magic comes from the fact that Reader has instances for Functor, Applicative and Monad:
instance Functor (Reader r) where
fmap f (Reader g) =
-- A `Reader` that applies `f` to the original `Reader`'s results
Reader (\r -> f (g r))
instance Applicative (Reader r) where
pure a =
-- A `Reader` that ignores its `r` argument and just produces
-- a fixed value.
Reader (\_ -> a)
Reader ff <*> Reader fa =
-- A `Reader` that "combines" two `Reader`s by feeding the same
-- `r` value to both, and then combining their results
Reader (\r -> ff r (fa r))
instance Monad (Reader r) where
return = pure
Reader fa >>= k =
-- A `Reader` that feeds the same `r` both to the original one
-- and to the one computed by the `k` function
Reader (\r -> k (fa r) r)
If you study these, you'll notice that what Reader is about is delaying the point of the program where you apply the wrapper r -> a function to an r. Normally, if you have a function of type r -> a and you want to get a value of type a, you have to feed the function an argument of type r. The Reader class instances allow you instead to supply functions that will be used to operate on the a ahead of time, and then supply the r in the end.
The ReaderT type and the MonadReader class (which has the ask :: MonadReader r m => m r method) are just more advanced versions of this.
A value of type m a where m is a Monad, can be thought of as a "monadic action". So ask doesn't take any parameters, it's just a value that you can bind (>>=) to extract some value from a Reader monad.
Look at the definition of ask for ReaderT in Control.Monad.Trans.Reader:
-- | Fetch the value of the environment.
ask :: (Monad m) => ReaderT r m r
ask = ReaderT return
ReaderT is just a data constructor that contains a value of type r -> m a, so ReaderT return is a value of type ReaderT r m r that contains a function, return (of the monad m).
In other words, ask here is a "monadic action" that extracts the value of stored inside the Reader.
ask >>= f
Which is
(ReaderT return) >>= f
Using definition of >>= for Reader, we get:
ReaderT $ \ r -> do
a <- runReaderT (ReaderT return) r
runReaderT (f a) r
Which reduces to
ReaderT $ \ r -> do
a <- return r
runReaderT (f a) r
Or
ReaderT $ \r -> runReaderT (f r) r
So, it passes the stored value along to decide the next action and also passes the value so the next actions can read it as it was before.
(If this wasn't clear, look for a Reader tutorial maybe)

Adding state to an Either

I have a function which is something like myFunction below:
data MyError = E1 | E2
f s = if s == "" then Left E1 else Right $ reverse s
g = (fmap reverse) . f
myFunction :: String -> Either MyError (String, String)
myFunction s = do
s1 <- f s
s2 <- g s1
return (s2, s2)
So it calls various other functions which are also in the Either monad, so everything is OK.
Now I have a situation where the type of one of the functions, say g, changes to
g :: CPRG r => r -> String -> (Either MyError String, r)
For reference, the "real-world" code is the decode function here and the function that changes is Jwe.rsaDecode (I'm adding RSA blinding to the decryption function).
As a result, myFunction needs to have the same type, so that I can pass in the CPRG and return it. I'm having trouble seeing how I can carry on using something like the Either monad in combination with passing the RNG, and still be able to extract the final state of the RNG in both the failure and success cases, so that it can be returned.
The type
r -> (Either e a, r)
is a monad transformer. In particular, it's the ExceptT transformer
newtype ExceptT e m a = ExceptT (m (Either e a))
We'll specialize it for State such that
r -> (Either e a, r)
~
ExceptT e (State r) a
So what is a monad transformer? Well, it turns out that often when you take two monads together and stack them you end up with yet another monad. It is not always the case and is a bit tricky to do in general (unlike Applicative where stacks of Applicative functors are always yet again Applicative functors).
That said, the library linked above, mtl, demonstrates a list of common "transformers" which encode common ways of stacking monads. Thus, ExceptT is one of these "recipes" and it is designed such that ExceptT e m a is a monad so long as m is also a Monad.
So now we can create a new type alias
type M r a = ExceptT MyError (State r) a
and write g as a function like
g' :: CPRG r => String -> M r String
g' s = do
r <- lift get -- lift "lifts" State monad computations up
let (e, r') = g r s
lift $ put r'
either throwError return e -- here we generalize an Either
-- into the M monad.

What's the absurd function in Data.Void useful for?

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.

Resources