Reputation: 9934
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
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