用途
本文档用于指导 R 函数 API 的设计、R 代码设计问题的评审、R 包函数的编写,以及参数顺序与命名决策的评估。其核心理念是:为人类而非计算机设计 R 函数,以降低认知负担、提升可预测性与可组合性。文中强调这些原则适用于任何 R 代码,而不限于 tidyverse 包。
主要能力
文档以「快速参考」表与大量正反例代码的形式,给出一系列可操作的设计模式:可预测的命名、清晰的参数、管道友好、类型稳定、枚举选项、副作用处理、复杂策略抽取等。
函数命名
- 使用祈使语气的动词,例如
mutate()、filter()、summarize();名词式构建器(如geom_point()、recipe())属于例外。 - 优先使用前缀而非后缀,因为前缀便于自动补全发现,例如
str_detect()、str_replace()、str_extract()、read_csv()、read_tsv()、read_delim();后缀用于同一主题的变体,例如map_int()、map_chr()、map_dbl()。 - 命名长度与使用频率成反比:高频用短名(
c()、n()、df),低频用描述性名称(create_bootstrap_samples()、validate_model_specification())。
参数设计
- 最重要的参数放在最前,例如
str_replace(string, pattern, replacement)、left_join(x, y, by);决定输出的参数靠前,例如read_csv(file, col_types, col_names)。 - 必填参数不设默认值;反例是让所有参数都有默认值。
...的位置很重要,应放在必填参数与可选参数之间,从而强制后续可选参数显式命名,例如my_function <- function(x, y, ..., verbose = FALSE, na.rm = TRUE)。- 默认值保持简短,复杂默认值用
NULL表示并在函数体内计算(如weights <- weights %||% rep(1, length(x))),而不是把复杂表达式直接写在签名里。 - 枚举字符串选项时使用
arg_match()配合字符向量默认值,例如method = c("fast", "accurate", "balanced"),首个值为默认值并完成校验。 - 标准化常用参数名:预测新数据用
new_data(而非 newdata、newData),缺失值处理用na_rm(而非 na.rm、rm.na),案例权重用weights(而非 wts、w),预测变量数据框用x(而非 predictors、features),结果变量用y(而非 response、target),公式接口数据用data(而非 df、dataset)。
输出模式
- 类型稳定性:输出类型应由输入类型而非输入值决定,例如
ifelse()会因条件值改变返回类型,而dplyr::if_else()保持一致。 - 模型函数的预测输出应为 tibble:与输入行数相同、行顺序相同、列名标准化为
.pred、.pred_class、.pred_lower。 - 用于副作用的函数应不可见地返回第一个参数(如写入文件的函数返回
invisible(x)),以便链式管道继续使用。
副作用
- 将副作用与计算分离:不要在计算函数里埋入打印或修改全局状态的代码;可用
verbose参数控制信息输出。 - 让副作用易于撤销:修改全局状态的函数应返回原值以便恢复(如
options()的用法示例)。
策略模式
- 避免用布尔标志表示策略,因为组合语义不清,例如
grepl()的 perl、fixed、ignore.case 组合。 - 对复杂选项使用策略对象与辅助函数,如
regex()、fixed(),主函数按对象类型分派处理。
显式优于隐式
- 避免依赖全局选项,例如不要从
getOption("na.action")隐式取值,而应提供带说明性默认值的显式参数。 - 当默认值重要时应告知用户,例如在时区默认取值时通过
cli::cli_inform()提示。
模型对象设计
- 最小化存储数据:只保存预测所需内容(如系数、因子水平),不要把整个训练集存入模型造成内存膨胀。
- 永不保存 call 对象,因为 call 可能内嵌整个数据集与环境。
- 使用规范的 S3 构造器:内部
new_my_model()、内部校验器validate_my_model()、面向用户的辅助函数my_model()。
矩阵子集
- 始终保留矩阵结构,使用
X[, 1, drop = FALSE]而非可能退化为向量的X[, 1]。
使用方式
文档提供「设计评审检查清单」,在评审 R 函数设计时逐项核对:函数名是否为祈使动词(构建器可为名词)、相关函数是否共享前缀、最重要参数是否靠前、主数据是否为第一个参数(管道友好)、必填参数是否无默认值、... 是否位于必填与可选参数之间、字符串选项是否用 arg_match() 配合枚举默认值、输出类型是否可由输入类型预测、副作用函数是否不可见返回输入、是否存在对全局选项或区域设置的隐藏依赖、策略变化是否用对象而非布尔标志、模型对象是否不存储训练数据与 call、矩阵子集是否使用 drop = FALSE。
适用场景
适合需要设计或评审 R 函数 API、编写 R 包函数、评估参数顺序与命名决策的开发者。文中示例以 tidyverse 与 tidymodels 生态为主,但原则声明适用于任意 R 代码。
限制
资料未提供具体的收费、价格、平台或效果信息,暂未提供。