Operator section for applicative use with <$> and <*>

Consider functions of the type a -> b -> c and applicative values a1, a2 :: (Applicative f) => fa .

I want to build a function that can be applied to functions of type a -> b -> c to get values ​​of type Applicative f :: fc . I can do it like this:

 g :: (Applicative f) => (a -> b -> c) -> fc g = \f -> f <$> a1 <*> a2 

(Explicit lambda is intentional, as I am considering building this function at any level, not just at the top level).

If I try to write g in point-free style:

 g = (<$> a1 <*> a2) 

I get the following compilation error:

 The operator `<$>' [infixl 4] of a section must have lower precedence than that of the operand, namely `<*>' [infixl 4] in the section: `<$> gen1 <*> gen2' 

I could write this failsafe implementation:

 g = flip (flip liftA2 a1) a2 

but I feel that it is less readable and easier to reorganize the implementation based on functions based on infix, for example, add a different argument than the change above to use liftA3 .

You can write a chain of songs:

 g = (<*> a2) . (<$> a1) 

This provides a dotless style and just add arguments, but they are added to the left, not to the right of them, so you lose the correspondence with the type of function (a -> b -> c) . Also, with a lot of arguments, you get a much longer expression than just using a lambda, as in the first implementation.

So, is there a good, easy way to write the section I want, or am I stuck in lambda?

+5
source share
2 answers

<*> works with the result <$> , therefore:

 g = (<*> a2) . (<$> a1) 
+7
source

I'm not sure that pointfree can be done better than using an explicit argument here, but a couple more ideas:

  • You can use flip infix:

     g = liftA2 `flip` a1 `flip` a2 
  • You can use >>> from Control.Category , which . flipped:

     g = (<$> a1) >>> (<*> a2) 
+6
source

All Articles