2013-07-08 69 views
1

您好我想实现这个Common Lisp的宏用Ruby 2.0.0-P247:是否有可能通过函数使用关键字参数

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

二进制测试功能需要两个参数和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

你使用Ruby 2.0吗? – Fred

+0

是Ruby 2.0.0-p247 – juanitofatas

回答

3

你并不需要宏来做到这一点。 Ruby有一个漂亮的动态运行时,所以只需使用面向对象设计涉及的消息传递语义并使用#send即可。

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

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

你可以尝试这样的事:

def binary_cmp(a, b, test_func: ->(a, b){ a > b }) 
    test_func.(a,b) 
end 
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 
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)) 
相关问题