您好我正在尝试在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
)默认值。
答案 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