In general, the monad use case doesn't assume that there's the possibility of "unwrapping". For Maybe it's fine and can be used to replicate monadic functionality. But there are other functors/monads, as you suggest, which make less sense.
Here's a pretty odd one:
data Needs r a = Needs { execute :: (a -> r) -> r }
In other words, a value x :: Needs Int String is a computation which can return an Int if you provide it a means to convert a String into an Int. You might conceptually say that it will give us a "complex" or composite "view" into values of type String given a "simple" or "atomic" view. For instance, length
(execute x) length :: Int
This type seems as though it almost certainly "contains" a value of type a (or String in the concrete example above). It might actually contain many such values. Here are three examples, the first two are the cases mentioned above. The third is similar to the None case with Maybes.
We could also imagine more exotic manipulations occurring inside of the Needs. For example
ex4 :: Needs (\view -> let n = view "Hello" in view (repeat n "world, ") \* n + 10)
It should also be clear that there's no way to "unwrap" a value of type Needs R A. This is obviously true if R and A are different types. You actually could imagine using mutable state, like a mutable vector v, to view all the As stored inside of a Needs
(execute ex4) (\a -> { push v a; () }) -- not really Haskell syntax
But this throws away all of that repeat and * and + nonsense in ex4. It's not really the same as a true "unwrap".
But Needs is still a monad.
pure :: a -> Needs r a
pure a = Needs (\view -> view a)
(>>=) :: Needs r a -> (a -> Needs r b) -> Needs r b
m >>= f = Needs (\view -> execute m (\a -> execute (f a) view))
So, Needs is an example of a Monad which cannot in general be unwrapped. Working with it is a little complex in most cases, but the monad operations help to consolidate a couple very common, useful operations on Needs.
Finally, I'll give up the ghost and note that Needs is known as the Continuation-Passing Monad. It helps you write code in CPS style without having to actually, deliberately pass continuations all around. This can be really useful for a few dumb-programmer tricks, but it's also a pretty useful framework for building embedded domain-specific languages.
Here's a pretty odd one:
In other words, a value x :: Needs Int String is a computation which can return an Int if you provide it a means to convert a String into an Int. You might conceptually say that it will give us a "complex" or composite "view" into values of type String given a "simple" or "atomic" view. For instance, length This type seems as though it almost certainly "contains" a value of type a (or String in the concrete example above). It might actually contain many such values. Here are three examples, the first two are the cases mentioned above. The third is similar to the None case with Maybes. We could also imagine more exotic manipulations occurring inside of the Needs. For example It should also be clear that there's no way to "unwrap" a value of type Needs R A. This is obviously true if R and A are different types. You actually could imagine using mutable state, like a mutable vector v, to view all the As stored inside of a Needs But this throws away all of that repeat and * and + nonsense in ex4. It's not really the same as a true "unwrap".But Needs is still a monad.
So, Needs is an example of a Monad which cannot in general be unwrapped. Working with it is a little complex in most cases, but the monad operations help to consolidate a couple very common, useful operations on Needs.Finally, I'll give up the ghost and note that Needs is known as the Continuation-Passing Monad. It helps you write code in CPS style without having to actually, deliberately pass continuations all around. This can be really useful for a few dumb-programmer tricks, but it's also a pretty useful framework for building embedded domain-specific languages.