[Concepts] 从 CovAnalysis 看 Extended CovScript 的 ECSX 扩展

在其他语言中,数据分析功能已经非常常见了,但 CovScript 一直没有这方面的支持
在目前比较常用的 Python 和 R,数据分析都是比较方便的
为了补齐这部分短板,我们引入了 CovAnalysis 框架

import analysis
var df = analysis.read_csv("tests/cwurData.csv")
var tc = "USA", tq = 10
df = df.filter(
    analysis::cond(
        country == tc &&
        quality_of_education.to_number() <= tq
    )
)
df.select(
    "institution",
    "quality_of_education"
).show()
df.aggregate(
    analysis.avg("score").as("score_avg")
).show()

可以看到,CovAnalysis 的代码风格和 CovScript 本身不太一样,是基于数据流的API,还有一部分函数式的风格
目前的测试是,对于 CSV 文件来说,CovAnalysis 在中等规模数据集上的性能是比 Pandas 还要强一些,更不要说 R 的 Dplyr 了

1 个赞

在上面展示的代码中,最显眼的莫过于 analysis::cond 这个“函数”
这其实是 ECS 的宏(Macro)语法
与传统语言的宏不同,ECS 的宏均定义在与包名同名的 .ecsx 文件中
covanalysis/analysis.ecsx at main · covscript/covanalysis · GitHub
ECSX 扩展实际上还是一个使用 CovScript 3 语法编写的源文件,但会在 ECS 编译器运行过程中被调用。ECSX 中需要定义一个入口函数:

function ecsx_main(hooks)
    hooks.insert("cond", my_hook)
end

入口函数的功能非常简单,即向 ECS 编译器注册可用的宏钩子(Macro Hooks),第一个参数是宏名,第二个参数是钩子处理函数:

function my_hook(ecs, ast, pos)
    # TODO
end

每一个钩子处理函数都需要有三个参数。第一个参数是 ECS 编译器对象,第二个参数为调用宏时传入的代码对应的 AST 子树,第三个参数为调用宏时代码所在的位置(方便报错)

报错也非常简单,比如要处理传入参数为空的情况:

if ast == null
    ecs.error(pos, "ECSX function require arguments")
    return
end

介绍完了 ECSX,再回到 analysis::cond 宏。这个宏看起来什么都没做,实际上会扫描 AST 中引用到的变量名,然后在生成代码时将变量名作为元信息传入 filter 函数,这样 CovAnalysis 就能知道在运行 filter 函数时应该从 DataFrame 中提取哪几个字段
从这里可以看出,ECSX 扩展是非常强大的。首先就是 ECSX 能拿到完整的 AST 子树,因此可以对 AST 做任何想要的分析和处理;其次就是 ECS 编译器不会对这部分 AST 子树进行任何处理和代码生成,所以是相当于把代码生成全部交给了 ECSX,有相当大的自由度
这就让 ECS 的宏与其他语言完全不同,不仅给予了类似元编程的自由度,这部分逻辑还是运行在编译期的,不会影响到运行时性能

1 个赞

这里如果 quality_of_education 写错成比如 quality_of_eduction,也会在运行时才报错是吗?

是的,这里主要的问题是若要在编译期报错,就需要在编译期解析数据,会不合理的拉长编译时间,不是做不到

1 个赞

的确是个取舍问题。不过如果仅解析数据头,代价不会太大?
从用户体验来看,如果以这种引用而非字符串的形式,用户也许会期望它有编译期检查的功能。
另外,以后如果要添加补全功能,比如在 quality_of_education 加点后,提示 to_number 函数等,也最好对数据作提前检查?

主要是 DataFrame 的来源比较多,在规划中还允许从 CSDBC 数据源读取,这种情况下再要求编译期分析,就属实不合理了
至于数据提前检查,若数据来源是数据库可能还好一些,但像 CSV 这种得需要读取整个文件才能确定某个 DataFrame 的数据类型
这部分补全确实比较困难,大多数都是运行时才能获取到具体的数据