这很容易在 Template Haskell 中实现,方法是使用haskell-src-meta包来解析准引用中的 Haskell 表达式。
{-# 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"
请注意,由于 Template Haskell 的工作原理,您不能从定义它的同一文件中使用准引用器,因此请将上述内容保存到其自己的模块中。
在 GHCi 中测试
*Main> :set -XTemplateHaskell
*Main> :set -XQuasiQuotes
*Main> [af|(+) (Just 3) (Just 8)|]
Just 11
*Main> [af|(+) (Just 6) Nothing|]
Nothing