Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A function similar to (>>=) but which returns a different monad

Tags:

haskell

monads

The type of (>>=) is

(>>=) :: Monad m => m a -> (a -> m b) -> m b

I want a function that has the type:

(Monad m, Monad n) => m a -> (a -> n b) -> n b

This function could be used to chain different monads together.

I faced this problem when I was trying to get 3000 from the command-line arguments -p 3000:

main = getArgs >>= (\args -> (elemIndex "-p" args) >>= (\id -> warpDebug (fromIntegral.read (args !! (id+1))) Ilm))

This clearly won't compile because getArgs returns an IO [String] and elemIndex returns a Maybe Int. A function of the above type could be used to elegantly solve this problem. My question is:

  • Is this function already defined? (Hoogle does not find any)
  • If there isn't, it's probably due to some reason. What is the reason then? Is this considered a bad practice? I think it's a better way than having to use a case expression.
like image 578
Abdulsattar Mohammed Avatar asked Dec 23 '11 09:12

Abdulsattar Mohammed


People also ask

Is a monad a function?

In functional programming, a monad is a software design pattern with a structure that combines program fragments (functions) and wraps their return values in a type with additional computation.

Is reduce a monad?

Reduce ( / , ⌿ ), also called Reduction or Insert, is a primitive monadic operator which takes a dyadic function operand, inserts it between the elements of the argument, and evaluates it into a single array in right-to-left order.

What is either monad?

In Error handling we have two possible paths either a computation succeeds or fails. The imperative way to control the flow is using exceptions and a try/catch block.

Is maybe a monad?

The Maybe sum type is a useful data type that forms a functor. Like many other useful functors, it also forms a monad.


2 Answers

Such a function doesn't exist. In fact, if you take n to be the identity monad, it would allow you to construct a function m a -> a, which clearly cannot be defined for all monads.

To address the general problem of "composing" two monads, you can look into monad transformers.

However, it seems overkill to use monad transformers in your example. You can simply define a function [String] -> Maybe Args (for some custom type Args - say Int in the example) which does the command line argument processing, then pattern match on the result (or use maybe) from within the IO monad.

like image 126
Paolo Capriotti Avatar answered Oct 05 '22 23:10

Paolo Capriotti


This function doesn't exist because it would not make sense for all monads. It is basically equivalent to a monad unpacking function Monad m => m a -> a--the only difference is that you immediately put it into another monad.

The reason this function is not defined for all monads is because it does not make sense for some of them. For example, take Maybe: the only way to unpack it would be to throw an error if you have Nothing, and runtime errors are looked down upon. A more extreme example would be IO--using a function that could "unpack" IO values would lead to weird and potentially nondeterministic behavior.

Thus, you do not have such a function in general. However, a lot of specific monads do come with such functions. A great example is runST; this is actually a safe way for dealing with state. You actually do have such functions for both Maybe and IO (fromJust and unsafePerformIO respectively), but they have the problems I outlined above and you should avoid them.

The solution to your problem, then, is to see if there exists such a function for whichever monads you're dealing with. If there does, check any potential pitfalls--does it generate runtime errors or cause weird behavior?

In your case, if you are absolutely sure that the Maybe is never Nothing, use fromJust. However, this is not generally good practice, so you should just stick to pattern matching the value out of the Maybe.

like image 21
Tikhon Jelvis Avatar answered Oct 06 '22 00:10

Tikhon Jelvis