以下代码是用javascript编写的。
这个问题涉及尝试深入研究一些类别理论,也许是哈克勒或者更熟悉这个问题的数学方面的人可以帮助我?
我试图围绕这样一个想法,即仿函数是保留结构的类别之间的映射。更具体地说 - 根据我的理解 - 编程语言中的仿函数是一个endofunctor。这意味着编程语言中的仿函数是态射,它将类型和函数映射到通常在编程语言中定义的更广泛的类型和函数类别中的子类别。
据我所知,仿函数(或指导者)也必须遵守某些通过促进构成和身份来保护结构的法律。
我发现创建一个我觉得保留结构的仿函数几乎是不可能的,并且遵守仿函数法则。事实上,我只是在javascript中真正认真编程,因此类型理论是我从未真正想过的(毕竟JS是无类型的)。
我做了这个简单的例子,将整数提升到一个最小的上下文中,映射在偶数上不起作用。换句话说,你可以使用你的作文进行映射,但是一旦你达到偶数,节目就结束了。
这看起来有点像是:
class noEvens {
constructor(x) {
this._val = x;
}
static of(x) {
return new noEvens(x);
}
isEven() {
return this._val % 2 === 0;
}
map(projF) {
return this.isEven() ? noEvens.of(null) : noEvens.of(projF(this._val));
}
}
但显而易见的是,在某些情况下,这不会影响在普通JS类别中应用于整数的合成。考虑一个简单地将一个加到整数的投影函数。
如果我将一个偶数提升到这个noEvens上下文然后加一个它会给我一个null的noEvens。但是,如果我首先将一个加到偶数,然后提起结果,它将导致奇数的noEvens。
根据我的理解,这两种途径都应该根据仿函数法来减少。它们显然不是因为每个环境中的相同映射不会产生相同的结果" noEvens.of(value)"被解除后。
所以我猜我的问题是,这是否意味着这不是一个仿函数?什么是这种情况(类型或其他)使它行为奇怪?
我想我只是感到困惑,因为它似乎是所有" noEvens"将价值提升到一个新的背景(子类别,无论如何),即使数字不存在,但显然某些途径不会通勤。
我发现"提升价值的想法"进入一个非常直观的新映射环境,它为您提供了很多处理条件的机会,而无需实现大量的冗余代码。但是我不想以虚伪的方式这样做,因为我遵守了一些正式的“仿函数法”系统。
在我对这种情况的分析中,我错过了什么类型系统和仿函数法?
答案 0 :(得分:1)
除了我的评论......
您可能会注意到您的几乎是仿函数类也不符合身份法。
const id = x => x;
new noEvens(2).map(id) // != new noEvens(2)
我的第一个想法是错误是允许首先构造包含偶数的noEvens对象。如果isEven检查是在构造函数中完成的,那么您可以满足ID法则。
class noEvens {
constructor(x) {
if (x % 2 === 0) {
this._val = null;
} else {
this._val = x;
}
}
static of(x) {
return new noEvens(x);
}
map(projF) {
if (this._val === null) {
return noEvens.of(null);
}
return noEvens.of(projF(this._val));
}
}
const id = x => x;
new noEvens(1).map(id)._val // ok: 1
new noEvens(2).map(id)._val // ok: null
但是,事实证明这个解决方案仍然不符合组成法。
const plusOne = x => x + 1;
// fmap f . fmap g == fmap (f . g) ?
new noEvens(1).map(plusOne).map(plusOne)._val // null
new noEvens(1).map(x => plusOne(plusOne(x)))._val // 3
所以最终我认为致命的缺陷是noEvens限制了它可以容纳的数据类型。正如Bergi所说,“通常的仿函数将能够包含任意数据。”因此,作为一个概念,noEvens作为一个概念,不能成为遵守组成法的算符。