函数作为模板中使用的参数haskell引用 [英] Functions as arguments to be used in template haskell quote
问题描述
这部分是针对为某个函数提供实例?的后续工作。但是,答案是全局定义函数或在引用中重写它。然而,我们将在<$ c $的范围内,为 f
使用 foo
C>让。这使我们几乎不可能定义f的多个全局版本。后者的解决方案,在报价中编写我们的功能,似乎相当于为功能写作。
那么,是否有任何提升函数的方法作为参数在模板Haskell引用中使用?
一个非常做作的例子:
$ b
{ - #Language TemplateHaskell# - }
导入 Language.Haskell.TH
foo ::(Int-> Int) - > Int - > ExpQ
foo fx = [| fx |]
$ bg :: ExpQ
g =
let
f =(\ x - > x + 1)
f'=(\ x' - > f(x')+ 1)
in foo f'0
将会失败:
foo.hs:5:11:
由于使用'Language.Haskell.TH.Syntax.lift'而产生的(Language.Haskell.TH.Syntax.Lift(Int - > Int))
的实例
在表达式中: Language.Haskell.TH.Syntax.lift f
在表达式中:
[| f x |]
pending(rn)[x,f]
在'foo'的等式中:
foo f x
= [| fx |]
pending(rn)[x,f]
只提取函数的结果,在编译时应用函数
在你的特殊情况下,因为你在编译时知道 ,所以 x
和 f
,你可以在编译时计算 fx
并且只拼接结果:
foo ::(Int-> Int) - > Int - > ExpQ
foo f x = [| $(lift $ f x)|]
- = lift $ f x
- foo f = lift。 f
这不会改变 f $ c的类型签名$ c>,但它要求你知道你要给
f
的所有参数。您需要为 lift
函数导入 Language.Haskell.TH.Syntax
。
将函数的表达式作为参数传递
如果您不能使用第一个解决方案,那么还有另一种方法。而不是传递函数,你现在传递一个函数作为参数的拼接:
foo :: ExpQ - > Int - > ExpQ
foo f x = [| $ f $ |
$ / code>
有两个缺点:首先,由于不是类型安全,检查splice是否真的展开为可应用于 Int
的东西。您需要更改您的调用代码,如下所示:
g :: ExpQ
g =
let
f = [| \x - > x + 1 |]
f'= [| \x' - > $ f x'+ 1 |]
in foo f'0
This is partially a followup to Lift instance for a function?. However, the answer there is to either globally define the function or to rewrite it inside the quotation. However, we will be using foo
a lot with different functions for f
from within the scope of a let
. This makes it just about impossible for us to define multiple global version of f. The latter solution, of writing our function within the quote, seem equivalent to writing a lift on functions.
So, is there any way of lifting functions taken as arguments to use in a template Haskell quotation?
A very contrived example:
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
Will fail with:
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]
Lifting functions is not possible. There are however two possible alternatives that might work for your:
Only lift the result of the function, apply the function at compile time
In your special case, because you know at compile time both x
and f
, you can just compute f x
at compile time and only splice the result:
foo :: (Int->Int) -> Int -> ExpQ
foo f x = [| $(lift $ f x) |]
-- = lift $ f x
-- foo f = lift . f
This doesn't change the type signature of f
, but it requires that you know all the arguments you want to give to f
. You'll need to import Language.Haskell.TH.Syntax
for the lift
function.
Pass an expression for a function as an argument
If you cannot use the first solution, there is another alternative. Instead of passing the function, you now pass a splice for a function as an argument:
foo :: ExpQ -> Int -> ExpQ
foo f x = [| $f x |]
There are two disadvantages: First, you loose type-safety because it isn't checked that the splice really expands to something that can be applied to an Int
. And you need to change your calling code, like this:
g :: ExpQ
g =
let
f = [| \x -> x+1 |]
f' = [| \x' -> $f x' + 1 |]
in foo f' 0
这篇关于函数作为模板中使用的参数haskell引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!