1

我一直在研究一个 R 包,它只是一个图形数据库的 REST API 包装器。我有一个函数createNode,它返回一个带有类node和的对象entity

# Connect to the db.
graph = startGraph("http://localhost:7474/db/data/")

# Create two nodes in the db.
alice = createNode(graph, name = "Alice")
bob = createNode(graph, name = "Bob")

> class(alice)
[1] "node"   "entity"
> class(bob)
[1] "node"   "entity"

我有另一个函数,createRel它在数据库中的两个节点之间创建关系。规定如下:

createRel = function(fromNode, type, toNode, ...) {
  UseMethod("createRel")
}

createRel.default = function(fromNode, ...) {
  stop("Invalid object. Must supply node object.")
}

createRel.node = function(fromNode, type, toNode, ...) {
  params = list(...)

  # Check if toNode is a node.
  stopifnot("node" %in% class(toNode))

  # Making REST API calls through RCurl and stuff.
}

允许用户以 key = value的...形式向关系中添加任意数量的属性。例如,

rel = createRel(alice, "KNOWS", bob, since = 2000, through = "Work")

这会在数据库中创建一个 (Alice)-[KNOWS]->(Bob) 关系,其中包含属性since及其through各自的值。from但是,如果用户使用键或to在参数中指定属性,R 就会对和...的类感到困惑。fromNodetoNode

用 key 指定一个属性from会混淆fromNode. 它正在使用createRel.default

> createRel(alice, "KNOWS", bob, from = "Work")

Error in createRel.default(alice, "KNOWS", bob, from = "Work") : 
Invalid object. Must supply node object. 
3 stop("Invalid object. Must supply node object.") 
2 createRel.default(alice, "KNOWS", bob, from = "Work") 
1 createRel(alice, "KNOWS", bob, from = "Work")

类似地,如果用户使用 key 指定属性to,则会对 的类产生混淆toNode,并在 处停止stopifnot()

Error: "node" %in% class(toNode) is not TRUE 
4 stop(sprintf(ngettext(length(r), "%s is not TRUE", "%s are not all TRUE"), 
  ch), call. = FALSE, domain = NA) 
3 stopifnot("node" %in% class(toNode)) 
2 createRel.node(alice, "KNOWS", bob, to = "Something") 
1 createRel(alice, "KNOWS", bob, to = "Something")

我发现明确设置参数createRel可以正常工作:

rel = createRel(fromNode = alice,
                type = "KNOWS",
                toNode = bob,
                from = "Work",
                to = "Something")
# OK

但我想知道我需要如何编辑我的createRel函数,以便以下语法可以正常工作:

rel = createRel(alice, "KNOWS", bob, from = "Work", to = "Something")
# Errors galore.

打开这个问题的 GitHub 用户提到它很可能与setAson dispatch 冲突,它的参数称为fromand to。一种解决方案是摆脱...并更改createRel为以下内容:

createRel = function(fromNode, type, toNode, params = list()) {
  UseMethod("createRel")
}

createRel.default = function(fromNode, ...) {
  stop("Invalid object. Must supply node object.")
}

createRel.node = function(fromNode, type, toNode, params = list()) {
  # Check if toNode is a node.
  stopifnot("node" %in% class(toNode))

  # Making REST API calls through RCurl and stuff.
}

但是,我想看看在进行此更改之前是否还有其他选择。

4

1 回答 1

2

不是真正的答案,但是...

问题是用户提供的参数“from”正在(部分)与形式参数“fromNode”匹配。

f = function(fromNode, ...) fromNode
f(1, from=2)
## [1] 2

规则在第 4.3.2 节中概述RShowDoc('R-lang'),其中命名参数精确匹配,然后部分匹配,然后未命名参数按位置分配。

除了使用单字母参数名称之外,很难知道如何强制执行精确匹配!实际上,对于泛型来说,这可能不像听起来那么陈词滥调——它x是一个非常通用的变量名。如果 'from' 和 'to' 是...的常见参数,您可以将参数列表更改为“fromNode, , ..., from, to”,检查函数体中是否缺少(from),然后采取行动因此; 我不认为这会令人愉快,而且用户总是会提供一个“来回”的论点。

虽然通过设置 global 来强制执行精确匹配(和错误,通过 warn=2)options()可能有助于调试(尽管到那时你可能知道你在寻找什么!)它对尝试编写的包作者没有帮助一般为用户工作的代码。

在 R-devel 邮件列表上询问是否是时候改变这种行为可能是合理的(在“几个版本”的时间尺度上);从制表符完成前的几天开始,部分匹配可能会作为“方便”日期。

于 2014-08-29T12:17:09.117 回答