I'm just getting started with template haskell.
I've written a function that takes a function a -> [b]
and generates an expression for a function b -> a
:
{-# OPTIONS_GHC -Wall -Wextra -Werror #-}
module Surjection where
import Language.Haskell.TH
import Data.Traversable
surj :: (Show a, Show b, Bounded a, Enum a) => (a -> [b]) -> Q Exp -- Q (TExp (b -> a))
surj f = fmap (LamCaseE . concat) . -- \case
forM [minBound .. maxBound] $ \a -> do
Just aName <- lookupValueName (show a)
forM (f a) $ \b -> do
Just bName <- lookupValueName (show b)
return $ Match (ConP bName []) (NormalB (ConE aName)) [] -- $(bName) -> $(aName)
This works, but it'd be nice if I could promise that it returns a function of that type, that is have it return a Q (TExp (b -> a))
rather than a Q Exp
.
Everything I've seen thus far about generating typed expressions uses splices and quasiquotes. Is there a way to generate it from template haskell constructors?
Oh hey, there's a TExp :: Exp -> TExp a
constructor in Language.Haskell.TH.Syntax
, so I can just use that:
surj f = fmap (TExp . LamCaseE . concat) ...
There's the downside that the type specified by TExp
only gets checked at splice time (kind of like a C++ template), but that's inherent to TH.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With