1

I have some function

bar :: MyType -> MyType -> [MyType]

I would like to have another function:

foo :: [MyType] -> [MyType]
foo xs = do x <- xs
            y <- xs
            bar x y

Is it possible to write foo without using the do notation? I was thinking about something like liftA2 but that won't work.

user1747134
  • 2,374
  • 1
  • 19
  • 26
  • 1
    All do notation can be rewritten with `>>=` and `return`, for this, there is even a special use function. – Willem Van Onsem Sep 06 '18 at 20:38
  • Right, you are technically correct. What I actually meant, was if I can rewrite it in some natural way using functions from `Control.Applicative` or `Control.Monad` and no lambdas. Rewriting by `>>=` usually requires many lambdas. – user1747134 Sep 06 '18 at 20:44
  • 1
    "was thinking about something like liftA2 but that won't work." Why not? – Mor A. Sep 06 '18 at 20:50
  • 2
    @M.Aroosi: mind that `bar` is a monadic type here, it is *not* `return (bar x y)`, but simply `bar x y`. – Willem Van Onsem Sep 06 '18 at 20:52
  • 1
    right, you could use `liftA2` and `join` tho. – Mor A. Sep 06 '18 at 20:52
  • Possible duplicate of [Replacing do by >>= for a scotty post](https://stackoverflow.com/questions/52147265/replacing-do-by-for-a-scotty-post) – AJF Sep 06 '18 at 21:11
  • Possible duplicate of [Desugaring do-notation for Monads](https://stackoverflow.com/questions/8019670/desugaring-do-notation-for-monads) – jberryman Sep 06 '18 at 22:36
  • For this function, `foo xs = bar <$> xs <*> xs` would appear to suffice, since `x` and `y` are independent of each other. This is what you would get with the `ApplicativeDo` extension. – chepner Sep 07 '18 at 03:20

2 Answers2

7

we can use the algorithmic conversion from do-blocks, as described in the Haskell report:

foo :: [MType] -> [MType]
foo xs = xs >>= \x -> xs >>= \y -> bar x y

But we can reduce the amount of lambda-expressions, by omitting the y variable:

foo :: [MType] -> [MType]
foo xs = xs >>= \x -> xs >>= bar x

and we can omit the x variable as well, by writing \x -> xs >>= bar x as (xs >>=) . bar

foo :: [MType] -> [MType]
foo xs = xs >>= ((xs >>=) . bar)

Or like @M.Aroosi says, we can use a combination of join :: Monad m => m (m a) -> m a and liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c:

foo :: [MType] -> [MType]
foo xs = join (liftA2 bar xs xs)
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
2

You may also use the following pattern for varying arities for bar:

Arity 2

-- bar :: [MType] -> [MType]
foo :: [MType] -> [MType]
foo xs = join $ bar <$> xs <*> xs

Arity 3

-- bar :: [MType] -> [MType] -> [MType]
foo :: [MType] -> [MType]
foo xs = join $ bar <$> xs <*> xs <*> xs

and so on.

I like this as it is easier to extend than the hardcoded liftA2.

Camsbury
  • 121
  • 3
  • 8