Haskell check if value exists in monad

I am wondering if there is an equivalent or something for null from lists generalized to monads. At the moment, I'm trying to find erroneous values ​​with == mzero . But such a check provokes false positives, since mzero /= Left "foo" .

Is there an elegant way to express what I want in standard libraries?

+7
haskell
source share
4 answers

The notion of "contains a value" is not written to the Monad class. In the end, Monad gives you something for the sequence ( >>= ) of actions (linking the previous result). And MonadPlus gives you a way to “shorten” the calculation using mzero (look at the laws and mplus ).

However, the ability to contain one or more values ​​usually goes hand in hand with the ability to dump all of these values ​​into something. Indeed, Data.Foldable contains a function, also called null :

 > import qualified Data.Foldable as F > > showAndTell :: (Show (ta), Foldable t) => ta -> IO () > showAndTell k = > putStrLn $ " F.null (" ++ show k ++ ") is " ++ show (F.null k) > main = do > putStrLn "Using F.null on 'empty' things:" > showAndTell $ (Left "Error" :: Either String Int) > showAndTell $ (Nothing :: Maybe Integer) > showAndTell $ ([] :: [Double]) > > putStrLn "" > putStrLn "Using F.null on 'filled' things:" > showAndTell $ (Right 123 :: Either String Integer) > showAndTell $ (Just 123 :: Maybe Integer) > showAndTell $ ([1,2,3] :: [Int]) 

Result:

 Using F.null on 'empty' things: F.null (Left "Error") is True F.null (Nothing) is True F.null ([]) is True Using F.null on 'filled' things: F.null (Right 123) is False F.null (Just 123) is False F.null ([1,2,3]) is False 

So you are looking for the Foldable part, not the Monad . This will only work on GHC 7.10 or higher, since Data.Foldable.null is entered into the 4.8.0.0 database. If you are stuck in an old version of GHC, you can use

 > isEmpty :: F.Foldable t => ta -> Bool > isEmpty = F.foldr (\_ _ -> False) True 
+12
source share

I cannot locally remember any simple function that works for all the monads Maybe , Either e , MaybeT m and ExceptT em , which are the main monas that I can think of having "erroneous values".

Since GHC 7.10, null actually generalized (before Foldable ), so it works on the first two.

For the last three ( Either e works with both methods) and converted versions of them, you can probably use the catchError function.

(Although the last two have Foldable instances, their null does the wrong thing.)

+5
source share

Definitely not from the monad. If you are looking for something like nonEmpty :: MonadPlus m => ma -> Bool , then this is not possible.

You will need to run a monadic calculation to find out if it is “empty”. But for the monad, you may need some input to run (for example, things like State or even just Reader ), and in the worst case IO you cannot start the monad from the outside. Now these examples are not MonadPlus on their AFAICR, but increase them with an error (for example, MaybeT ), and suddenly an obvious definition of what it means for them to be "empty" appears, but the same restrictions still apply. Since the unknown monad may be one of them, you cannot get any information.

A possible signature could be nonEmpty :: MonadPlus m => ma -> m Bool (although I'm not sure if this has a reasonable implementation). But I don’t think you need it, since it doesn’t actually generalize null ; you will return to [False] or [True] for lists (or perhaps even [True, True, True, ...] with the same number of elements as the input), which is a bit strange.

I think monads are on the wrong "axis of generalization" for null ; you need an abstraction that characterizes containers better than Monad (many monads are containers, but there are so many other things that are very different from each other, so code that runs on arbitrary monads cannot accept properties similar to a container). A generalization of Foladable , as happened in GHC-7.10, seems like a pretty good bet. You can probably create a class like CanBeEmpty that allows a few more things than Foldable ; I do not know that this already exists.

+5
source share

The idiomatic task is not to try to directly determine zero, but to provide the behavior you want in the case of zero.

This is what mplus or equivalent (in the latest preludes) <|> do; it triggers an action to run when the first action is not performed. This is the same as catchError on those monads that catchError supports. This is similar to the general idiom in shell or perl programming foo || bar foo || bar , meaning run foo, and then run bar if foo failed.

Beware of the list monad that it will run all the parameters, because that is how the list monad works in order to simulate "several possibilities."

I often use <|> on MaybeT or EitherT to model left-biased choices, i.e. "try all these alternatives one at a time until you succeed."

Remember that using <|> for EitherT cancels the error message (because it turns the failed calculation into a subsequent one); if you want to save the error message and handle it somehow, again catchError which you need.

+2
source share

All Articles