
A couple of times I find myself wishing for an easy way to transform a function by picking and choosing which of its operators are lifted. For example, consider f <$> x1 <*> pure x2 <*> x3 <*> pure x4 we can put all the details of this into f itself f' x1 x2 x3 x4 = f <$> x1 <*> pure x2 <*> x3 <*> pure x4 and then just write f' x1 x2 x3 x4 I think it might be nice to have a series of transformation functions that made this easy to write. Something like a series of operator like so f' = f <$_$_> where it would be read that f' is a lifted f such that the first argument is lifted, the second is not, the third is, and the fourth is not (this is consistent with f <$> returning a being a lifted f with first argument being lifted). This would make code such as the following flip (go finalX finalY) y `liftM` mx = go <__$_> finalX finalY mx y https://github.com/snoyberg/conduit/blob/be803218b5b2acaad2eb720ca3a27a4d073... much more robust to write (how it gets written now depends very much on the number of arguments, their order, which ones are lifted, etc.), a whole lot easier to read, and don't even get me started on the points free use (go <__$_>)! A library could easily provide the first six or so variants (2^6 = 64 functions). If they were really useful the compiler could provide the rest. <$> :: (a -> b) -> f a -> f b <$$> :: (a -> b -> c) -> f a -> f b -> f c <$_> :: (a -> b -> c) -> f a -> b -> f c <_$> :: (a -> b -> c) -> a -> f b -> f c ... Cheers! -Tyson PS: It would be nice to also have ones that work with f being lifted. That is like how we have <$> for an unlifted f and <*> for a lifted f. <*> :: f (a -> b) -> f a -> f b <**> :: f (a -> b -> c) -> f a -> f b -> f c <*_> :: f (a -> b -> c) -> f a -> b -> f c <_*> :: f (a -> b -> c) -> a -> f b -> f c ... A bit of a pain here is that <**> is actually already taken as <*> with reversed arguments. Possibly this would call for something like this instead <$^> :: (a -> b) -> f a -> f b <$^^> :: (a -> b -> c) -> f a -> f b -> f c <$^_> :: (a -> b -> c) -> f a -> b -> f c <$_^> :: (a -> b -> c) -> a -> f b -> f c ... and <*^> :: f (a -> b) -> f a -> f b <*^^> :: f (a -> b -> c) -> f a -> f b -> f c <*^_> :: f (a -> b -> c) -> f a -> b -> f c <*_^> :: f (a -> b -> c) -> a -> f b -> f c ... where they are prefixed by $ or * to indicate what type f is and then _ encodes an unlifted argument position and ^ a lifted argument position.