49

Is there a built-in function with signature :: (Monad m) => m a -> a ?

Hoogle tells that there is no such function.

Can you explain why?

  • 2
    Related: [taking out a value out of a monad? haskell](http://stackoverflow.com/questions/7314789/taking-out-a-value-out-of-a-monad-haskell) – Jan Dec 19 '11 at 21:26
  • 16
    There isn't, but there is a function that turns functions expecting an `a` into functions expecting an `m a`: `(=<<) :: Monad m => (a -> m b) -> (m a -> m b)`. Invert your expectations, and you will be fine. =) – Daniel Wagner Dec 19 '11 at 21:33
  • 3
    In the same vein as what Daniel Wagner said, `liftM :: Monad m => (a -> b) -> (m a -> m b)` allows a "regular" function to accept a monadic value as input, but in exchange it must output a monadic value rather than a "regular" value. – Dan Burton Dec 19 '11 at 22:39
  • rather, `liftM` makes a regular function `f :: a -> b` work "inside the monad" without knowing it, such that `liftM f` outputs `m b` values given `m a` values. the regular function `f` still outputs the same `b` values as it is defined to. can't do anything else. – Will Ness Feb 29 '20 at 20:43

8 Answers8

55

A monad only supplies two functions:

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

Both of these return something of type m a, so there is no way to combine these in any way to get a function of type Monad m => m a -> a. To do that, you'll need more than these two functions, so you need to know more about m than that it's a monad.

For example, the Identity monad has runIdentity :: Identity a -> a, and several monads have similar functions, but there is no way to provide it generically. In fact, the inability to "escape" from the monad is essential for monads like IO.

hammar
  • 138,522
  • 17
  • 304
  • 385
  • Just out of curiosity, what is the algebraic property of the monad that ensures the existence of such a function? (I come from category theory, be gentle) – fosco May 05 '19 at 17:53
  • @FoscoLoregian There's no real reason, that's just how it's defined. If it doesn't have these functions, it's not a monad. – schuelermine Jun 12 '19 at 10:55
27

There is probably a better answer than this, but one way to see why you cannot have a type (Monad m) => m a -> a is to consider a null monad:

data Null a = Null

instance Monad Null where
    return a = Null
    ma >>= f = Null

Now (Monad m) => m a -> a means Null a -> a, ie getting something out of nothing. You can't do that.

Owen
  • 38,836
  • 14
  • 95
  • 125
  • 5
    On the other hand this fact doesn't prevent `fromJust` from existence. It returns contents of a `Just` and raises an exception in case of `Nothing`. Your `Null` monad could simply always raise an exception on calling such imaginary monad unwrapping function. – Jan Dec 19 '11 at 21:32
  • 15
    @Jan: On the other other hand that doesn't make either function a good idea. `fromJust` is terrible and would be better not existing. – C. A. McCann Dec 19 '11 at 21:51
  • 3
    @C.A.McCann I +1 your comment partly because `fromJust` is bad... but mainly because you used "other other hand". – Adam Wagner Dec 19 '11 at 23:54
  • 1
    Agee with C.A. McCann; the fact that the proposed method for the `Monad` class would have to be implemented as raising an exception for many classes is evidence enough that it should not be part of the class. If we actually had some examples of "monad that we can extract from" that we wanted to cope, then we could create a subclass of Monad to tackle them and put the operation there. – Luis Casillas Dec 20 '11 at 00:26
  • `fromJust` has its uses, just not in robust code. I use it when there's no point in continuing on failure. For example, when the UI definition file is missing for an mplayer frontend. – György Andrasek Dec 20 '11 at 03:59
  • 2
    @GyörgyAndrasek: Even in cases like that, I'd suggest `fromMaybe (error "UI definition file missing")` rather than `fromJust`. – C. A. McCann Dec 20 '11 at 14:45
  • @CAMcCann, it's been several years, but that would be wrong too! One reasonable way is `maybe (throwIO "UI definition file missing") pure`. `error` and `throw` are lousy ways to handle runtime conditions; among other issues, laziness can make their timing hard to predict. – dfeuer Apr 13 '16 at 15:34
  • 1
    Coming back around, no, there is not a better answer than this. A single counterexample is sufficient to disprove a conjecture, and you've provided the smallest counterexample. – dfeuer Aug 25 '18 at 01:15
  • 1
    One suggestion: to be *strictly* lawful, use `Null >>= f = Null`. This ensures `undefined >>= return = undefined` as required by the identity law. – dfeuer Aug 25 '18 at 01:18
19

This doesn't exist because Monad is a pattern for composition, not a pattern for decomposition. You can always put more pieces together with the interface it defines. It doesn't say a thing about taking anything apart.

Asking why you can't take something out is like asking why Java's Iterator interface doesn't contain a method for adding elements to what it's iterating over. It's just not what the Iterator interface is for.

And your arguments about specific types having a kind of extract function follows in the exact same way. Some particular implementation of Iterator might have an add function. But since it's not what Iterators are for, the presence that method on some particular instance is irrelevant.

And the presence of fromJust is just as irrelevant. It's not part of the behavior Monad is intended to describe. Others have given lots of examples of types where there is no value for extract to work on. But those types still support the intended semantics of Monad. This is important. It means that Monad is a more general interface than you are giving it credit for.

Carl
  • 26,500
  • 4
  • 65
  • 86
14

Suppose there was such a function:

extract :: Monad m => m a -> a

Now you could write a "function" like this:

appendLine :: String -> String
appendLine str = str ++ extract getLine

Unless the extract function was guaranteed never to terminate, this would violate referential transparency, because the result of appendLine "foo" would (a) depend on something other than "foo", (b) evaluate to different values when evaluated in different contexts.

Or in simpler words, if there was an actually useful extract operation Haskell would not be purely functional.

Luis Casillas
  • 29,802
  • 7
  • 49
  • 102
  • 2
    [unsafePerformIO](http://hackage.haskell.org/package/base-4.7.0.1/docs/System-IO-Unsafe.html#v%3aunsafePerformIO) does just this. – ely Dec 21 '14 at 00:28
  • @ely, unsafePerformIO does it by making your program be no-longer purely functional. – codeshot Oct 28 '18 at 11:27
  • @codeshot that is the whole point. In the answer here, it's mentioned that `extract` would also make the program no longer purely functional, by virtue of violating referential transparency. – ely Oct 29 '18 at 12:59
7

Is there a build-in function with signature :: (Monad m) => m a -> a ?

If Hoogle says there isn't...then there probably isn't, assuming your definition of "built in" is "in the base libraries".

Hoogle tells that there is no such function. Can you explain why?

That's easy, because Hoogle didn't find any function in the base libraries that matches that type signature!

More seriously, I suppose you were asking for the monadic explanation. The issues are safety and meaning. (See also my previous thoughts on magicMonadUnwrap :: Monad m => m a -> a)

Suppose I tell you I have a value which has the type [Int]. Since we know that [] is a monad, this is similar to telling you I have a value which has the type Monad m => m Int. So let's suppose you want to get the Int out of that [Int]. Well, which Int do you want? The first one? The last one? What if the value I told you about is actually an empty list? In that case, there isn't even an Int to give you! So for lists, it is unsafe to try and extract a single value willy-nilly like that. Even when it is safe (a non-empty list), you need a list-specific function (for example, head) to clarify what you mean by desiring f :: [Int] -> Int. Hopefully you can intuit from here that the meaning of Monad m => m a -> a is simply not well defined. It could hold multiple meanings for the same monad, or it could mean absolutely nothing at all for some monads, and sometimes, it's just simply not safe.

Community
  • 1
  • 1
Dan Burton
  • 53,238
  • 27
  • 117
  • 198
  • 2
    I don't see how `Monad m => m a -> a` lacks meaning in any way that wouldn't also apply to `>>=` or `return` or `fail`. You could always say that the "meaning" of the operation isn't well-defined in advance of knowing the full implementation that `m` provides for its inclusion in the Monad type class. For your list example, a function with type `Monad m => m a -> a` could very well mean any of the things you suggest -- and *any* of them *might* be valid. You could always use `newtype` to tweak the behavior for *your* application, but denying even the chance to do it seems too severe. – ely Dec 21 '14 at 00:14
  • @ely, For Monad m => m a -> a it needs to be possible to implement a function with that type signature for *each* monad m, and which each work for *all* types a. That's not possible. – codeshot Oct 28 '18 at 11:26
  • @codeshot Sure it's possible. It just might not be useful or might require ugly things like sentinel values or some notion of an `Any` type etc. etc. For example, Haskell could define a value `Placeholder` that has any possible type, and then you could create a really gross baked-in implementation of a Haskell runtime that essentially does a try / catch at *runtime* and if a monadic extraction operation would fail, it return `Placeholder` instead, and the compiler can be made aware of this. It's totally gross and has many downsides, but the point is that it's absolutely possible. – ely Oct 29 '18 at 15:33
  • Like anything else, it's just a matter of tradeoffs. If you're willing to have "any" type things floating around and monadic operations that are "implicitly unsafe" but still strongly typed, then such a thing would be fine. Most people choose Haskell to avoid that tradeoff, so nobody wants it and prefers the language to not support it, but there is no grand mathematical reason why it can't, it just depends on what you're happy to trade off to get it. – ely Oct 29 '18 at 15:35
  • if it does try/catch at runtime then it doesn't implement the specified type, you'd need `Monad m => m a -> Either a` but you'd also need to be able to query the argument to see if you can get an `a` and you can't do that because the `Monad` typeclass doesn't have a query function. If your function was of type `(Monad m, Nullable m) => m a -> Either a` then you could implement that. Or `(Monad m, Nullable m, Monoid a) => m a -> a` - these cover some of the implementation choices you gave - but you see those have different types *because* they allow more things. – codeshot Apr 19 '19 at 08:09
6

Because it may make no sense (actually, does make no sense in many instances).

For example, I might define a Parser Monad like this:

data Parser a = Parser (String ->[(a, String)])

Now there is absolutely no sensible default way to get a String out of a Parser String. Actually, there is no way at all to get a String out of this with just the Monad.

Cubic
  • 14,902
  • 5
  • 47
  • 92
2

There is a useful extract function and some other functions related to this at http://hackage.haskell.org/package/comonad-5.0.4/docs/Control-Comonad.html

It's only defined for some functors/monads and it doesn't necessarily give you the whole answer but rather gives an answer. Thus there will be possible subclasses of comonad that give you intermediate stages of picking the answer where you could control it. Probably related to the possible subclasses of Traversable. I don't know if such things are defined anywhere.

Why hoogle doesn't list this function at all appears to be because the comonad package isn't indexed otherwise I think the Monad constraint would be warned and extract would be in the results for those Monads with a Comonad instance. Perhaps this is because the hoogle parser is incomplete and fails on some lines of code.

My alternative answers:

  1. you can perform a - possibly recursive - case analysis if you've imported the type's constructors
  2. You can slink your code that would use the extracted values into the monad using monad >>= \a -> return $ your code uses a here as an alternative code structure and as long as you can convert the monad to "IO ()" in a way that prints your outputs you're done. This doesn't look like extraction but maths isn't the same as the real world.
codeshot
  • 1,183
  • 1
  • 9
  • 20
0

Well, technicaly there is unsafePerformIO for the IO monad.

But, as the name itself suggests, this function is evil and you should only use it if you really know what you are doing (and if you have to ask wether you know or not then you don't)

hugomg
  • 68,213
  • 24
  • 160
  • 246
  • 2
    There is also `unsafeHead` for the List monad...(oh wait, it's just called `head`...but it is similarly, though not quite as drastically, unsafe.) – Dan Burton Dec 21 '11 at 05:23
  • @DanBurton Actually, `unsafePerformIO` is often safer; it may launch rockets to destroy the moon, but at least it doesn't cause your program to crash. – jpaugh Sep 28 '17 at 03:22
  • neither head nor unsafePerformIO can be used on the argument of a function of type `Monad m => m a -> a`. In order to use either you have to know the type of `m`: `IO a -> a` or `[] a -> a` – codeshot Apr 19 '19 at 08:16