如何编写高阶函数以将方法添加到给定函数?

时间:2019-03-20 23:21:35

标签: julia

让我们假设我想编写一个接受任何关联运算符⊕的函数,并向其中添加方法,以便我可以用函数替换任何值。这些其他方法的语义如下:

  • 如果随后将运算符应用于两个函数fg,则结果应为首先将fg(独立)应用于其运算符的函数参数,然后将applies应用于结果。
  • 如果一个参数是函数f,但另一个参数是任何非函数值x,则结果是一个函数,该函数首先将f应用于其参数,然后将applies应用于结果和x

我可以用代码表示为:

associative!(⊕) = begin
    ⊕(f::F, y) where F<:Function = (xs...) -> f(xs...) ⊕ y
    ⊕(x, g::G) where G<:Function = (xs...) -> x ⊕ g(xs...)
    ⊕(f::F, g::G) where {F<:Function, G<:Function} = (args...) -> f(args...) ⊕ g(args...)
    ⊕(f::F, y, zs...) where F<:Function = f ⊕ ⊕(y, zs...)
    ⊕(x, g::G, zs...) where G<:Function = x ⊕ ⊕(g, zs...)
    ⊕(f::F, g::G, zs...) where {F<:Function, G<:Function} = f ⊕ ⊕(g, zs...)
end

但是,当我尝试编译此函数时,出现以下错误:

ERROR: syntax: cannot add method to function argument ⊕

我知道我可以编写一个高阶函数,该函数返回基于给定函数的 new 函数/运算符。例如:

associative(⊞) = begin
    let ⊕(x) = x
        ⊕(x, y) = x ⊞ y
        ⊕(x, y, zs...) = ⊕(x⊞y, zs...)
        associative!(⊕)
        ⊕
    end
end

如果我在这里内联associative!的定义,那么associative可以正常工作,我可以写:

⊕ = associative(+)
⊗ = associative(*)

f(x) = 3⊗x ⊕ 1
f(1) # 4
f(cos)(0) # 4

但是我认为最好有一个变异版本。我认为将associate!重写为宏是可以的,但实际上似乎没有什么需要在这里使用宏。因此,是否可以将其作为高阶函数来执行?如果可以,怎么做?

2 个答案:

答案 0 :(得分:1)

我不知道如何书写您的符号,但是这是否会使您对想要的东西有所了解?

=QUERY(A:B, "select * where A = 'Customer'")

答案 1 :(得分:0)

这里发生了一些事情。首先要注意的是⊕(<args...>) = <body...>的第一个实例将创建一个新函数并将其绑定到。但是,它显然不会为创建新的绑定。我猜这就是为什么错误消息中提到是一个函数参数的原因,但是无论如何这都是一个红色的提示-它只会创建一个新函数,而不是对现有函数进行突变。

this thread的结尾处,我们看到了first hint at a solution。为了动态地向函数别名添加方法,我们基本上需要使用与为任意数据类型定义可调用对象相同的语法:

(::typeof(⊕))(<args...>) = <body...>

通过此更改,我们得到了另一个错误:

Global method definition around ... needs to be placed at the top level, or use "eval"

在同一线程中再进一步一点,我们看到这是由于Julia 0.6之后的某个时间所引起的,因此我们now need to @eval这些表达式。现在我们涉及@eval,我们需要牢记以下几点:

  • 我们需要使用拼接对$⊕的引用
  • $前面的似乎干扰了Julia并将其识别为中缀运算符。因此,我们需要改用功能(前缀)表示法。

将其放在一起,最终得到如下结果:

@eval (::typeof($⊕))(f::F, y) where F<:Function = (xs...) -> $⊕(f(xs...), y)

如果我们真的想使用中缀符号,可以在let内使用@eval绑定:

@eval let ⊕ = $⊕
    (::typeof($⊕))(f::F, y) where F<:Function = (xs...) -> f(xs...) ⊕ y
    .
    .
    .
end