Reputation: 139038
In Monads for natural language semantics, Chung-Chieh Shan shows how monads can be used to give a nicely uniform restatement of the standard accounts of some different kinds of natural language phenomena (interrogatives, focus, intensionality, and quantification). He defines two composition operations, A_M
and A'_M
, that are useful for this purpose.
The first is simply ap
. In the powerset monad ap
is non-deterministic function application, which is useful for handling the semantics of interrogatives; in the reader monad it corresponds to the usual analysis of extensional composition; etc.
This makes sense. The secondary composition operation, however, has a type signature that just looks bizarre to me:
(<?>) :: (Monad m) => m (m a -> b) -> m a -> m b
(Shan calls it A'_M
, but I'll call it <?>
here.) The definition is what you'd expect from the types; it corresponds pretty closely to ap
:
g <?> x = g >>= \h -> return $ h x
I think I can understand how this does what it's supposed to in the context of the paper (handle question-taking verbs for interrogatives, serve as intensional composition, etc.). What it does isn't terribly complicated, but it's a bit odd to see it play such a central role here, since it's not an idiom I've seen in Haskell before.
Nothing useful comes up on Hoogle for either m (m a -> b) -> m a -> m b
or m (a -> b) -> a -> m b
.
Does this look familiar to anyone from other contexts? Have you ever written this function?
Upvotes: 3
Views: 443
Reputation: 8116
This reminds me of the loeb
function:
> loeb :: Functor a => a (a x -> x) -> a x
> loeb x = fmap (\a -> a (loeb x)) x
loeb
ties knots. What that means is that if a
is some kind of container, loeb
makes a container from a container of rules saying how to make each element from the final result.
<?>
is similar but instead of applying the rules to its own final result it applies the rules to another container, so it's no longer circular.
Upvotes: 1
Reputation: 77384
Part of the reason it looks strange may be the (m a -> b)
part--that's actually a restriction from the most polymorphic type inferred for the given implementation, and taken out of context would be nonsensical for a monad. The most general type looks like this:
> :t (\g x -> g >>= \h -> return $ h x)
(\g x -> g >>= \h -> return $ h x) :: (Monad m) => m (t -> a) -> t -> m a
A more general version of this can be written without using monads at all:
a'_F :: (Functor f) => f (a -> b) -> a -> f b
a'_F g x = fmap ($ x) g
It doesn't seem to be relevant here, but a type like f a -> b
does resemble the second argument to the cobind operation on a comonad:
(=>>) :: (Comonad w) => w a -> (w a -> b) -> w b
Upvotes: 6
Reputation: 1
Just playing around in the ghci, I tried out the following:
> [length, sum, maximum, minimum, const 666] <?> [1, 2, 3]
[3, 6, 3, 1, 666]
> Nothing <?> Nothing
Nothing
> Just (maybe 0 (^2)) <?> Just 7
49
> Just (maybe 0 (^2)) <?> Nothing
0
> :m + Control.Monad.Instances
> (((+2) >>=) <?> 3) (^) -- (3+2)^3
125
> (((+2) .) <?> 3) (^4) -- (3^4)+2
83
> ((. (+2)) <?> 3) (^4) -- (3+2)^4
625
I think I have actually written the list specific version of this. Of all these examples, I find the list version the most enlightening toward the general case.
Upvotes: 4