haskell - ¿Es posible usar un azúcar sintáctico para un functor aplicativo?
syntactic-sugar template-haskell (3)
En ''Programación aplicativa con efectos'' de McBride y Paterson, introducen un poco de azúcar sintáctico encantador para levantar una función pura:
[| f x y z |]
para
f <$> x <*> y <*> z
y recuerdo a alguien en otro lugar que usa li fwxyz il
o il fvwxyz li
, y pensé / esperaba que eso pudiera deberse a que podría definirse usando alguna característica de lenguaje existente y una definición astuta de li
y il
.
No puedo encontrar ninguna referencia a esto más allá del documento, y suponiendo que [|
y |]
no es probable que aparezca en ghc pronto, ¿es posible implementar li
y il
alguna manera? No puedo pensar en un tipo sensible para ellos, así que asumo que necesitaría Template Haskell o similar, pero no sé lo suficiente para lograrlo. [af| fxy ]
[af| fxy ]
estaría bien, pero no sé si es posible antes de empezar a intentarlo, y ciertamente necesito ayuda si lo es.
Creo que this es lo que estás buscando. Si recuerdo correctamente, también ha habido una discusión en la lista de correo de haskell-cafe con respecto a este estilo de aplicaciones aplicativas.
El enfoque de Haskell de la Plantilla para esto fue escrito por Matt Morrow y luego mantenido por mí, en el paquete de cotizaciones aplicativos . Lo usas como [i| fxyz |]
[i| fxyz |]
, así que está razonablemente cerca de la idea original de McBride y Paterson.
(Posible inconveniente: el nombre no debería ser seguido por su código, de lo contrario no funcionará. No estoy seguro de qué tan importante es este trato, personalmente).
Esto es bastante fácil de implementar en Template Haskell usando el paquete haskell-src-meta para analizar la expresión de Haskell en la casi cita.
{-# 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"
Tenga en cuenta que debido a cómo funciona Template Haskell, no puede usar el quasiquoter desde el mismo archivo en el que está definido, así que guarde lo anterior en su propio módulo.
Pruebas en GHCi
*Main> :set -XTemplateHaskell
*Main> :set -XQuasiQuotes
*Main> [af|(+) (Just 3) (Just 8)|]
Just 11
*Main> [af|(+) (Just 6) Nothing|]
Nothing