robkuz
robkuz

Reputation: 9934

Uplifting strategies when working with Functors

Assume that I have a function

foo :: a -> b -> c -> d -> e
foo a b c d = somefn a b c d

and some functions that return me a, b, c and d repsectively

getA :: a
getB :: b
getC :: f c
getD :: d

only that the function returning c is return a functor with c

now I have call site like

callfoo = foo getA getB getC getD

obviously that wont work as getC returns a functor of c and not c itself. So the only way seems to be

callfoo = (foo getA getB) <$> getC <*> getD

Apart from the fact that the simple call to foo gets lost here the signature changes as well to callfoo :: f e. One way to keep it simple is to (extract getC) but this is evil and will get you in a special compartment in Haskell-hell. I know.

My general question is: How do I handle situations where I mostly work with non-functorial values but then suddenly one of the values forces me to uplift all the other values as well?

Upvotes: 3

Views: 67

Answers (1)

Daniel Wagner
Daniel Wagner

Reputation: 153162

You can use do syntax:

do
    c <- getC
    return (foo getA getB c getD)

If you turn on ApplicativeDo, this will use the efficient fmap form rather than the potentially inefficient >>= and return form.

There is a quasiquoter on Hackage for idiom brackets which would let you write

[i| foo (pure getA) (pure getB) getC (pure getD) |]

Otherwise, there is little sugar available. There are many ways to spell your operation with existing combinators, which generally trade off between being generically applicable in all situations and being compact. Some examples include:

flip (foo getA getB) getD <$> getC
(\c -> foo getA getB c getD) <$> getC
foo getA getB <$> getC <*> pure getD
foo <$> pure getA <*> pure getB <*> getC <*> pure getD

Upvotes: 1

Related Questions