Codata 是 Data 的对偶概念。通过结构归纳你处理有限的 data。通过余归纳你处理可能是无限的Codata(但不总是)。
无论如何,如果你不能适当地定义一个有限的 toString 或相等性,那么它就是 Codata:
- 我们能定义无限流的 toString 吗?不能,我们需要一个无限的字符串。
- 我们总能为两个无限流定义外延相等性吗?不能,那将永远需要时间。
我们无法为流执行上述操作,因为它们是无限的。但即使是潜在的无限也会导致不可判定性(即我们无法明确地给出相等性的答案或者无法明确地给出一个字符串)。所以无限的流是 Codata。我认为您的第二个问题更有趣,函数是 codata 吗?
Lisper 说“代码即数据”,因为 S-表达式等特征允许像处理数据一样操作程序。显然,我们已经有了 Lisp 的字符串表示形式(即源代码)。我们还可以取一个程序并检查它是否由相等的 S-表达式组成(即比较 AST)。这是数据!
但是,让我们停止思考代表我们代码的符号,而是开始思考我们程序的意义。看下面这两个函数:
(fn [a] (+ a a))
(fn [a] (* a 2))
无论输入什么,它们都会产生相同的结果。我们不应该关心一个使用*
而另一个使用+
。除非它们仅适用于有限数据(相等性仅比较输入输出表),否则不可能计算任意两个任意函数是否具有扩展相等性。数字是无限的,所以这仍然无法解决我们上面的问题。
现在让我们考虑将函数转换为字符串。假设我们可以在运行时访问函数的源表示形式。
(defn plus-two [a] (+ a 2))
(defn plus-four [a] (plus-two (plus-two a)))
(show-fn plus-four)
现在,引用透明性说我们可以取代函数调用,将其替换为函数体,用变量替换,程序始终给出相同的结果。让我们对plus-two
进行此操作:
(defn plus-four [a] (+ (+ a 2) 2))
(show-fn plus-four)
哦,结果不同了。我们打破了引用透明性。
所以我们也不能为函数定义toString或相等性。这是因为它们是codata!
以下是我发现有助于更好地理解codata的一些资源: