是否可以使用关键字参数传递函数

时间:2013-07-08 12:26:42

标签: ruby lisp common-lisp

您好我正在尝试在Ruby 2.0.0-p247中实现这个Common Lisp宏:

(defmacro binary-cmp (a b &key (test-func '>))
  `(funcall #',test-func ,a ,b))

二进制测试函数,它接受2个参数和1个关键字参数test_func,而test_func默认为gt proc。

gt    = -> (a, b) { a > b }
lt    = -> (a, b) { a < b }
equal = -> (a, b) { a == b }

def binary_cmp (a, b, test_func: gt)
  test_func.(a, b)
end

但这不起作用,因为binary_cmp无法看到外面:gt

我该怎么做才能做到这一点?可能吗?或者有一种常见的做法吗?非常感谢你。

修改

我需要关键字参数的原因是我的参数列表有5个参数,也许用户只需要默认的测试函数(比如lt),或者有人想要使用(gt)默认值。

4 个答案:

答案 0 :(得分:5)

这个Lisp代码在某些方面很糟糕:

(defmacro binary-cmp (a b &key (test-func '>))
  `(funcall #',test-func ,a ,b))
  • 它不应该是一个宏。它应该是一个功能。

  • 可以更简单地编写宏。

不需要FUNCALL表单,因为它不添加任何功能。由于按设计,test-func需要是函数名称(FUNCTION#'需要函数名称),我们只需删除FUNCALL#'即可。在Lisp语法中,列表的第一个元素是函数名。

(defmacro binary-cmp (a b &key (test-func '>))
  `(,test-func ,a ,b))

作为一种功能,它只是:

(defun binary-predicate (a b &key (predicate '>))
  (funcall predicate a b))

答案 1 :(得分:3)

你真的不需要宏来做这件事。 Ruby有一个非常动态的运行时,所以只需使用OO设计涉及的消息传递语义并使用#send

def binary_cmp (a, b, test_func = :>)
  a.send(test_func, b)
end

binary_cmp(42, 7, :<) # => false

答案 2 :(得分:2)

这与函数或关键字参数或宏完全无关。 gt是一个局部变量。局部变量是它们定义的范围的本地变量,在本例中是脚本体。如果需要全局变量,则需要使用全局变量:

$gt    = -> (a, b) { a > b }
$lt    = -> (a, b) { a < b }
$equal = -> (a, b) { a == b }

def binary_cmp (a, b, test_func: $gt)
  test_func.(a, b)
end

或者,您可以使用嵌套范围。 Ruby中唯一创建嵌套作用域的是块,因此您需要使用块:

gt    = -> (a, b) { a > b }
lt    = -> (a, b) { a < b }
equal = -> (a, b) { a == b }

define_method(:binary_cmp) do |a, b, test_func: gt|
  test_func.(a, b)
end

答案 3 :(得分:1)

您可以尝试这样的事情:

def binary_cmp(a, b, test_func: ->(a, b){ a > b })
  test_func.(a,b)
end