Reputation: 1429
I know it is possible, to pattern match against (named) constructors like so:
f1 :: Maybe a -> Bool
f1 Nothing = False
f1 (Just x) = True -- in reality have something that uses x here
f2 :: [a] -> Int
f2 [] = False
f2 x = True
How can I write such a function for general Alternative
s similar to
f :: (Alternative m) => m a -> Bool
f empty = False
f x = True
If I try this, I get the error Parse error in pattern: empty
. Which makes sense, I guess, as empty
as a function here and not a constructor. But how can I accomplish this for general Alternative
s idiomatically?
Edit 1:
My actual goal is to define a Monad
instance (and probably also a MonadPlus
instance) for a custom result type. Instead of the basic Either Error Result
type, it should support a Maybe Error
(and if possible also other Alternative
s like [Error]
) as error type and also some Applicative
as result type in order to support lazy evaluation, for example with the result type (Maybe Error, [Tokens])
of a tokenizer.
I'd like something similar to
instance (Alterantive mErr, Applicative mRes) => Monad (mErr e, mRes a) where
return x = (empty, pure x)
(empty, pure x) >>= f = f x
(err, x) >>= f = (err, x)
Upvotes: 4
Views: 365
Reputation: 34398
Slipping in an Eq
constraint, as in mithrandi's answer, is indeed the best that can be done. In any case, it is worth emphasising that it comes at a cost: we are now stuck with an Eq
constant that would be unnecessary were we merely pattern match against, say, []
or Nothing
. A common way to avoid this problem is using null :: Foldable t => t a -> Bool
. Here, however, that option is not great either, as Foldable
is largely unrelated to Alternative
and rather alien to your use case. In particular, there is no guarantee that, in the general case, there will be just one value for which null
holds, which means it might conceivably hold for values that aren't the empty
of the relevant Alternative
instance.
Ultimately, then, the only tool that would fully fit the requirements might well be some Alternative
subclass with an isEmpty
method. I don't think that exists anywhere, and the power-to-weight ratio doesn't seem encouraging when it comes to conjuring such a thing.
Upvotes: 1
Reputation: 146
It is in fact possible using -XPatternSynonyms
and -XViewPatterns
:
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ViewPatterns #-}
import Control.Applicative (empty)
pattern Empty :: (Eq (m a), Alternative m) => m a
pattern Empty <- ((==) empty -> True)
f :: (Eq (m a), Alternative m) => m a -> Bool
f Empty = False
f _ = True
Upvotes: 2
Reputation: 1650
The best you can do is:
f :: (Eq (m a), Alternative m) => m a -> Bool
f x | x == empty = False
| otherwise = True
Upvotes: 5