我有一个函数,它给出了一个Name
函数,它增加了它,产生了另一个函数应用于其他一些东西(细节不太相关):
mkSimple :: Name -> Int -> Q [Dec]
mkSimple adapteeName argsNum = do
adapterName <- newName ("sfml" ++ (capitalize . nameBase $ adapteeName))
adapteeFn <- varE adapteeName
let args = mkArgs argsNum
let wrapper = mkApply adapteeFn (map VarE args)
-- generates something like SFML $ liftIO $ ((f a) b) c)
fnBody <- [| SFML $ liftIO $ $(return wrapper) |]
return [FunD adapterName [Clause (map VarP args) (NormalB fnBody) []]]
where
mkArgs :: Int -> [Name]
mkArgs n = map (mkName . (:[])) . take n $ ['a' .. 'z']
-- Given f and its args (e.g. x y z) builds ((f x) y) z)
mkApply :: Exp -> [Exp] -> Exp
mkApply fn [] = fn
mkApply fn (x:xs) = foldr (\ e acc -> AppE acc e) (AppE fn x) xs
这样可行,但从外部传递适配器功能所具有的args数量是很繁琐的。有一些TH函数来提取args的数量?我怀疑它可以通过reify来实现,但我不知道如何实现。
谢谢!
答案 0 :(得分:6)
当然,你应该可以做到
do (VarI _ t _ _) <- reify adapteeName
-- t :: Type
-- e.g. AppT (AppT ArrowT (VarT a)) (VarT b)
let argsNum = countTheTopLevelArrowTs t
...
where
countTheTopLevelArrowTs (AppT (AppT ArrowT _) ts) = 1 + countTheTopLevelArrowTs
countTheTopLevelArrowTs _ = 0
以上只是我的想法,可能不太正确。
答案 1 :(得分:1)
jberryman的答案略有改进,处理(Ord a) -> a -> a
等类型限制:
arity :: Type -> Integer
arity = \case
ForallT _ _ rest -> arity rest
AppT (AppT ArrowT _) rest -> arity rest +1
_ -> 0
用法:
do (VarI _ t _ _) <- reify adapteeName
let argsNum = arity t