(Speaking of Void
as the type with no values, which is different to the type with just one value, usually called Unit.)
In Haskell streaming libraries like streaming or pipes, there are data types that represent "a source of values of type a
that, once exhausted, returns a value of type r
". Something like Producer a m r
(The m
is a base monad but that's not relevant here.)
Having producers return with a value (of a type unrelated to the type of values they emit while running) is actually quite useful. For example, you can define a "streaming splitter" as a function with type:
streamingSplit :: Producer a m r -> Producer a m (Producer a m r)
This function segments the producer without having to accumulate in memory all the elements preceding the split.
Now, what if we want to express at the type level that a producer never stops producing stuff? We can make it return a value of type Void
, like Producer a m Void
.
Another possible use-case. Suppose you have a higher-order function that takes a callback that might fail. Something like:
-- does something with the wrapped callback, maybe emit a log message or whatever
takesACallback :: (a -> IO (Either e r)) -> a -> IO (Either e r)
What if we want to define a version of takesACallback
for functions a -> IO r
that never fail? Getting into and out of the Either
is a hassle, and incurs in an spurious pattern-match when getting the value out.
Using Void
we can start by turning the a -> IO r
into a a -> IO (Either Void r)
, pass it into takesACallback
, and then remove the "fake" error branch on the Either using the absurd :: Void -> a
function.
takesACallback':: (a -> IO r) -> a -> IO r
takesACallback' callback = fmap (either absurd id)
. takesACallback (fmap Right . callback)
Here's an example of this trick on Hackage.
Void
- no matter if you call themNoReturn
or anything else - a functiona -> Void
in Haskell cannot be meaningful defined – Uncommercialunit
) and its only value (()
), that would be of better use. – Emfvoid
results intoUnit
– Uncommerciallet f :: a -> Void; f x = f x
) - as I said it's a pointless function - totally useless (how is crashing your program the same as having avoid
function in C???) – UncommercialVoid
I always mean Haskell's Void, an empty type, and nevervoid
type from C family. – VillainyUnit
route or just stick with what you have – UncommercialVoid
. For examples,Maybe Void
is equivalent to()
(without undefined), but how can that be used?Either a Void
is equivalent toa
, but I again can't think of an example where that would really help. – Villainy