函数作为模板中使用的参数haskell引用 [英] Functions as arguments to be used in template haskell quote

查看:102
本文介绍了函数作为模板中使用的参数haskell引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这部分是针对为某个函数提供实例?的后续工作。但是,答案是全局定义函数或在引用中重写它。然而,我们将在<$ 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 ,但它要求你知道你要给 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆