I got accustomed to using a <> b
where a
and b
take arguments.
> const ["a"] <> const ["b"] $ True
["a","b"]
Why there is no a <|> b
as well?
> const ["a"] <|> const ["b"] $ True
<interactive>:64:13:
No instance for (Alternative ((->) Bool))
arising from a use of ‘<|>’
In the expression: const ["a"] <|> const ["b"]
In the expression: const ["a"] <|> const ["b"] $ True
In an equation for ‘it’: it = const ["a"] <|> const ["b"] $ True
We'd like to express something like "if the result type is Alternative
, then a function returning that type is Alternative
too". This isn't right, however, because only * -> *
types can be Alternative
.
We might try to remedy our problem by saying that the result type should be f a
for some Alternative f
, but that's still not good, because the type for which we'd like to define the instance also has to have kind * -> *
.
Actually, we just want to define an Alternative
instance for the composition of ((->) r)
and some Alternative f
. We can generalize this notion slightly to the following:
import Data.Functor.Compose
instance (Applicative f, Alternative g) => Alternative (Compose f g) where
empty = Compose $ pure empty
Compose a <|> Compose b = Compose $ liftA2 (<|>) a b
Unfortunately there is already a different Alternative
instance for Compose f g
in the transformers
library, and it clashes with the above instance.
Alternatively, we could notice that ReaderT r m
is the same thing as Compose ((->) r) m
(modulo newtype
wrapping), and fortunately the right instance is already exported by transformers
:
instance Alternative m => Alternative (ReaderT r m)
So we can do the following:
import Control.Monad.Reader
runReaderT (lift ["a"] <|> lift ["b"]) True
-- ["a", "b"]
runReaderT (empty <|> lift (Just 0)) True
-- Just 0