20

In McBride and Paterson's 'Applicative programming with effects' they introduce some lovely syntactic sugar for lifting a pure function:

[| f x y z |]

for

f <$> x <*> y <*> z

and I recall someone somewhere else using li f w x y z il or il f v w x y z li, and I thought/hoped that might be because it could be defined using some existing language feature and cunning definition of li and il.

I can't find any reference to this beyond the paper, and assuming that [| and |] aren't likely to turn up in ghc any time soon, is it possible to implement li and il somehow? I can't think of a sensible type for them, so I assume I'd need Template Haskell or similar, but don't know nearly enough to accomplish this. [af| f x y ] would be fine, but I don't know whether it's possible before I start attempting it, and certainly need help if it is.

AndrewC
  • 32,300
  • 7
  • 79
  • 115
  • 10
    I'm sure [she](http://hackage.haskell.org/package/she) can do it. – Daniel Wagner Aug 18 '12 at 00:25
  • 2
    You might want to have a look at [Template Haskell](http://www.haskell.org/haskellwiki/Template_Haskell). – Luis Casillas Aug 18 '12 at 01:00
  • 2
    I find I use this less than I thought I would: I probably overuse `$` to start with, and `<*>` is a very handy way of sperating the function arguments: I've discovered I often end up writing `glab <$> getsome values fromthis <*> getmore values fromthat` anyway. I'm still very much enjoying all the applicative stuff; I was wrong to think the syntax was in my way. – AndrewC Sep 03 '12 at 00:53

3 Answers3

16

I think this is what you are looking for. If I remember correctly there has also been a discussion on the haskell-cafe mailing list regarding this style of applicative applications.

Jan Christiansen
  • 3,153
  • 1
  • 19
  • 16
14

This is pretty easy to implement in Template Haskell by using the haskell-src-meta package to parse the Haskell expression in the quasi-quotation.

{-# LANGUAGE TemplateHaskell #-}

import Language.Haskell.TH
import Language.Haskell.TH.Quote
import Language.Haskell.Meta (parseExp)

import Control.Applicative ((<*>), (<$>))

af = QuasiQuoter
    { quoteExp  = parseAf
    , quotePat  = undefined
    , quoteType = undefined
    , quoteDec  = undefined
    }

parseAf :: String -> Q Exp
parseAf s = case parseExp s of
    Right ex -> applyExp ex
    Left err -> fail err

applyExp :: Exp -> Q Exp
applyExp (AppE f@(AppE _ _) a) = [|$(applyExp f) <*> $(return a)|]
applyExp (AppE f a) = [|$(return f) <$> $(return a)|]
applyExp _ = fail "invalid expression in af"

Note that due to how Template Haskell works, you can't use the quasiquoter from the same file where it's defined, so save the above to its own module.

Testing in GHCi

*Main> :set -XTemplateHaskell
*Main> :set -XQuasiQuotes
*Main> [af|(+) (Just 3) (Just 8)|]
Just 11
*Main> [af|(+) (Just 6) Nothing|]
Nothing
shang
  • 24,642
  • 3
  • 58
  • 86
  • 1
    That is truly lovely, yes. This is my favourite notation out of the two, partly because it's clearer what's going on in the syntax and partly because it's doing syntactic sugar by desugaring, which feels more like the right thing to do. Applicative is great, and this makes the syntax as good-lloking as the concept. Thanks. I'm off to refactor a project now to use applicative. mmmmmmmm. – AndrewC Aug 18 '12 at 17:34
8

The Template Haskell approach to this was written by Matt Morrow and then maintained by me, in the applicative-quoters package. You use it as [i| f x y z |], so it's reasonably close to McBride and Paterson's original idea.

(Possible drawback: the name i should not be shadowed by your code, else it won't work. Not sure how big a deal this is, personally).

Ben Millwood
  • 6,754
  • 24
  • 45