函数作为模板haskell引用中使用的参数

时间:2014-09-02 08:15:41

标签: haskell template-haskell

这部分是Lift instance for a function?的后续行动。但是,答案是全局定义函数或在引号内重写它。但是,我们会在foo的范围内对f使用不同功能的let。这使得我们几乎不可能定义f的多个全局版本。后者在引用中编写函数的解决方案似乎等同于在函数上编写一个提升。

那么,有没有办法提升函数作为参数在模板Haskell引用中使用?


一个非常设计的例子:

foo.hs

{-# Language TemplateHaskell #-}
import Language.Haskell.TH

foo :: (Int->Int) -> Int -> ExpQ
foo f x = [|f x|]

g :: ExpQ
g = 
    let 
        f = (\x -> x+1)
        f' = (\x' -> f(x') + 1)
    in foo f' 0

将失败:

foo.hs:5:11:
    No instance for (Language.Haskell.TH.Syntax.Lift (Int -> Int))
      arising from a use of ‘Language.Haskell.TH.Syntax.lift’
    In the expression: Language.Haskell.TH.Syntax.lift f
    In the expression:
      [| f x |]
      pending(rn) [x, f]
    In an equation for ‘foo’:
        foo f x
          = [| f x |]
            pending(rn) [x, f]

2 个答案:

答案 0 :(得分:4)

无法提升功能。但是,有两种可能适合您的替代方案:

仅解除函数的结果,在编译时应用函数

在您的特殊情况下,因为您在编译时知道 xf,所以您只需在编译时计算f x并且只能拼接结果:

foo :: (Int->Int) -> Int -> ExpQ
foo f x  = [| $(lift $ f x) |]
--       = lift $ f x
-- foo f = lift . f

这不会更改f的类型签名,但它要求您知道要为f提供的所有参数。您需要为Language.Haskell.TH.Syntax功能导入lift

将函数的表达式作为参数传递

如果你不能使用第一种解决方案,还有另一种选择。现在,您不是传递函数,而是将函数的拼接作为参数传递:

foo :: ExpQ -> Int -> ExpQ
foo f x = [| $f x |]

有两个缺点:首先,你没有松开类型安全性,因为没有检查拼接是否真的扩展到可以应用于Int的东西。你需要改变你的调用代码,如下所示:

g :: ExpQ
g = 
    let 
        f =  [| \x -> x+1 |]
        f' = [| \x' -> $f x' + 1 |]
    in foo f' 0

答案 1 :(得分:0)

对此的最佳答案是将一个表达式传递给一个函数,该函数首先对这些表达式求值,然后求解外部函数,例如: 头(掉落3个“ Sikandar”) 现在,这里的head是function,并且也删除了带有表达式的函数,因此将首先在内部函数中进行求值,因此drop的结果将从“ andar”中删除3个字符,并将这些结果传递给head所以从剩下的字符串头将是一个...