In Haskell, there is:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
Is there a function:(?)
bind2 :: Monad m => m a -> m b -> (a -> b -> m c) -> m c
Not quite, but you could use
bind2 :: Monad m => m a -> m b -> (a -> b -> m c) -> m c
bind2 x y f = join $ liftM2 f x y
This is what do notation is meant for.
bind2 :: (Monad m) => m a -> m b -> (a -> b -> m c) -> m c
bind2 ma mb f = do
a <- ma
b <- mb
f a b
It's so simple that I probably wouldn't even define an extra operator for it, rather I'd just use do notation directly.
or, using only first principles (>>=), like this (try it in ghci)
Prelude> :set +t
Prelude> let bind2 x y f = x >>= \ a -> y >>= \ b -> f a b
bind2 :: Monad m => m a -> m a1 -> (a -> a1 -> m b) -> m b
Prelude> let bind2 x y f = do a <- x ; b <- y ; f a b
bind2 :: Monad m => m t -> m t1 -> (t -> t1 -> m b) -> m b
Related
I'm new to Monads and was trying to write an add function and I'm unsure why this doesn't work. When using monads, is there a specific way you need to return a value?
monadd :: (Monad m, Num b) => m b -> m b -> m b
monadd mx my = mx >>= (\x -> my >>= (\y -> (x + y)))
You want to use pure (more general form of return)
monadd :: Monad m => Num a => m a -> m a -> m a
monadd mx my = mx >>= (\x -> my >>= (\y -> pure (x + y)))
The right-hand side (continuation) of >>= must always return a monadic action. But when you add x + y :: a you have a number. You need pure (x + y) :: m a to turn it into a monadic action:
monadd :: Monad m => Num a => m a -> m a -> m a
monadd mx my = mx >>= (\x -> my >>= (\y -> pure (x + y)))
^^^ ^ ^^^ ^ ^^^^^^^^^^^^
m a a m a a m a
You can equivalently write it in do-notation
monadd :: Monad m => Num a => m a -> m a -> m a
monadd mx my = do
x <- mx
y <- my
pure (x + y)
Actually. This doesn't require Monad. Applicative (n-ary lifting) is sufficient:
monadd :: Applicative m => Num a => m a -> m a -> m a
monadd = liftA2 (+)
Reminder that Functor lifts a unary function and Applicative lifts constants and n-ary functions (where liftA0 = pure and liftF1 = fmap):
liftA0 :: Applicative f => (a) -> (f a)
liftF1 :: Functor f => (a -> b) -> (f a -> f b)
liftA2 :: Applicative f => (a -> b -> c) -> (f a -> f b -> f c)
liftA3 :: Applicative f => (a -> b -> c -> d) -> (f a -> f b -> f c -> f d)
You only need Monad when there is a dependency between the computations. Notice that in your case the my computation does not dependent on the result of the mx computation.
If m b depended on the output of m a it would become a -> m b. Then Monad is required:
dependency :: Monad m => (a -> b -> c) -> m a -> (a -> m b) -> m c
dependency (·) as bs = do
a <- as
b <- bs a
pure (a · b)
When using monads, is there a specific way you need to Return a value?
Yes, you will need to wrap x and y back in a monadic context, with return :: Monad m => a -> m a, so:
monadd :: (Monad m, Num b) => m b -> m b -> m b
monadd mx my = mx >>= (\x -> my >>= return (x+y)))
Since the two operations of the monad mx and my operate independently of each other however, Applicative is sufficient, you can implement this as:
monadd :: (Applicative f, Num b) => f b -> f b -> f b
monadd mx my = (+) <$> mx <*> my
or through liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c:
monadd :: (Applicative f, Num b) => f b -> f b -> f b
monadd = liftA2 (+)
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)
bind :: Monad m => m a -> (a -> m b) -> m b
-- how do you use >=> to write bind?
I am absolutely so confused, I understand how both of these works but I cant even get started.
I tried all the following alternatives:
bind1 a b = (b a)
bind2 a b = (a >=> b)
bind3 a b = (b >=> a)
bind4 a b = (a b)
but every single attempt raises an error. Where can i possibly start on this question?
Since >>= has 2 parameters, and >=> has 3, how can I use >=> to write >>= when there is 1 less parameter?
First I'd suggest renaming the type parameters so the final result matches:
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)
bind :: Monad m => m a -> (a -> m c) -> m c
Now we have a b -> m c in the first signature and a -> m c in the second; that suggests renaming also a to b:
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)
bind :: Monad m => m b -> (b -> m c) -> m c
That leaves the main difference as having an extra argument a. But we evidently don't need that, so we might as well specialize it to the information-less type () (or any other single-value type):
(>=>) :: Monad m => (() -> m b) -> (b -> m c) -> (() -> m c)
bind :: Monad m => m b -> (b -> m c) -> m c
() -> m x is actually isomorphic to m x alone:
addDummyArg :: a -> (() -> a)
addDummyArg c () = c
rmDummyArg :: (() -> a) -> a
rmDummyArg f = f ()
And it's just a matter of using those conversion functions to adapt the functions to each other.
Since >>= has 2 parameters, and >=> has 3, how can I use >=> to write >>= when there is 1 less parameter?
Each function in Haskell has one parameter. You can interpret >=> , as a function that has as first parameter something of type a -> m b and the second something of b -> m c, the a -> m c is the "result" function.
What you here can do is manipulate the first parameter of bind into a function that accepts a parameter, and then provide that parameter, something like:
bind :: Monad m => m a -> (a -> m b) -> m b
bind ma f = (const ma >=> f) undefined
Here with const ma, we thus create a function that takes a parameter we do not care about, then we construct an a -> m c by using >=> and we call it with undefined (or some other value) to produce the m c value.
Functor has
(a -> b) -> m a -> m b
Applicative has
f (a -> b) -> f a -> f b
Monad has
m a -> (a -> m b) -> m b
But, Is there extended monad type that has
m a -> m (a -> m b) -> m b
or
m (a -> m b) -> m a -> m b
?
A Monad constraint is sufficient to implement a (sensible) function with that type signature:
foo :: Monad m => m (a -> m b) -> m a -> m b
foo mf ma = do
f <- mf
a <- ma
f a
or, if you prefer:
foo' :: Monad m => m (a -> m b) -> m a -> m b
foo' mf ma = mf >>= \f -> ma >>= f
This means that your proposed operation, even though it looks like a generalization of the usual >>= bind operation, isn't actually a generalization. Any >>= operation can be written in terms of foo, and any foo operation can be written in terms of >>=, so they are operations of equivalent "power".
In contrast, the other operations are not of equivalent power. Any applicative operation <*> can be written in terms of >>= and return, but you can't in general implement >>= in terms of <*>, so >>= is a strictly more powerful operation, etc.
I've got a function that's doing something currently working with particular datatypes. I was wondering if I could make it a general. Here's a generalised version of it's signature:
f :: Monad m => ((a -> b) -> c -> d) -> (a -> m b) -> m c -> m d
If the above can't be written, perhaps the more restricted version can?
f2 :: Monad m => ((a -> a) -> b -> b) -> (a -> m a) -> m b -> m b
No, it is impossible, at least without non-termination or unsafe operations.
The argument is essentially similar to this one: we exploit f to inhabit a type which we know can't be inhabited.
Assume there exists
f :: Monad m => ((a -> b) -> c -> d) -> (a -> m b) -> m c -> m d
Specialize c ~ ()
f :: Monad m => ((a -> b) -> () -> d) -> (a -> m b) -> m () -> m d
Hence
(\g h -> f (\x _ -> g x) h (return ()))
:: Monad m => ((a -> b) -> d) -> (a -> m b) -> m d
Speciazlize d ~ a.
(\g h -> f (\x _ -> g x) h (return ()))
:: Monad m => ((a -> b) -> a) -> (a -> m b) -> m a
Speclialize m ~ Cont t
(\g h -> runCont $ f (\x _ -> g x) (cont . h) (return ()))
:: ((a1 -> b) -> a) -> (a1 -> (b -> r) -> r) -> (a -> r) -> r
Take h = const
(\g -> runCont $ f (\x _ -> g x) (cont . const) (return ()))
:: ((r -> b) -> a) -> (a -> r) -> r
Hence
(\g -> runCont (f (\x _ -> g x) (cont . const) (return ())) id)
:: ((r -> b) -> r) -> r
So, the type ((r -> b) -> r) -> r is inhabited, hence by the Curry-Howard isomoprhism it corresponds to a theorem of propositional intuitionistic logic. However, the formula ((A -> B) -> A) -> A is Peirce's law which is known to be non provable in such logic.
We obtain a contradiction, hence there is no such f.
By contrast, the type
f2 :: Monad m => ((a -> a) -> b -> b) -> (a -> m a) -> m b -> m b
is inhabited by the term
f2 = \ g h x -> x
but I suspect this is not what you really want.
There's a problem. Knowing c doesn't give you any information about which as will be passed to (a -> b). You either need to be able to enumerate the universe of as or be able to inspect the provided a arguments with something like
(forall f. Functor f => ((a -> f b) -> c -> f d)
In which case it becomes almost trivial to implement f.
Instead of trying to implement f in general, you should try to generalize your functions like ((a -> b) -> c -> d) to see if you can replace them with lenses, traversals, or something similar.
In Haskell's Monads, I can easily define the operator (>=>) as :
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
f >=> g = \x -> f x >>= g
I also know that (>>=) can be expressed using (>=>): Let's call (>>=) as (..):
(..) :: Monad m => m a -> (a -> m b) -> m b
m .. k = m >=> \_ -> k
However something is not right ... could someone point what?
The idea of using a constant function (that is, \_ -> -- etc.) to make a function out of the argument which isn't a function so that you can pass it to (>=>) is sound. There are just two issues. Firstly, you are doing it to the wrong argument, as the one which isn't a function is m:
GHCi> :t \m k -> (\_ -> m) >=> k
\m k -> (\_ -> m) >=> k :: Monad m => m b -> (b -> m c) -> a -> m c
Secondly, (>=>) gives you a function (of type a -> m c in the demo just above). You have to apply it to something to get a result type that matches the one of (>>=). As that argument is irrelevant (you are ultimately feeding it to a constant function) you can just use ():
GHCi> :t \m k -> ((\_ -> m) >=> k) ()
\m k -> ((\_ -> m) >=> k) () :: Monad m => m b -> (b -> m c) -> m c
And that's it. I find it slightly prettier to use the const function rather than writing \_ ->, and so I would write it as:
(>>..) :: Monad m => m a -> (a -> m b) -> m b
m >>.. k = (const m >=> k) ()
The solution is the following:
(..) :: Monad m => m a -> (a -> m b) -> m b
m .. k =
(const m >=> k) undefined
Using const we're lifting an operation of type m a to whatever -> m a. This lifted version does not give a damn, what we pass to it so it might as well be the undefined.