{-# LANGUAGE TemplateHaskell, QuasiQuotes #-}

-- | Idiom brackets. Vixey's idea.

module Control.Applicative.QQ.Idiom (i) where

import Control.Applicative
import Language.Haskell.Meta (parseExp)
import Language.Haskell.TH.Lib
import Language.Haskell.TH.Quote
import Language.Haskell.TH.Syntax

-- ghci> [$i| (,) "foo" "bar" |]
-- [('f','b'),('f','a'),('f','r'),('o','b'),('o','a'),('o','r'),('o','b'),('o','a'),('o','r')]
i :: QuasiQuoter
i = QuasiQuoter { quoteExp = applicateQ }

applicateQ :: String -> ExpQ
applicateQ s = case either fail unwindE (parseExp s) of
                  x:y:xs -> foldl
                              (\e e' -> [|$e <*> $e'|])
                              [|$(return x) <$> $(return y)|]
                              (fmap return xs)
                  _ -> fail "applicateQ fails."

unwindE :: Exp -> [Exp]
unwindE = go []
  where go acc (e `AppE` e') = go (e':acc) e
        go acc e = e:acc