JavaScript 中的函子实现
Functor implementation in JavaScript
我尝试在 JavaScript 中实现一个 Functor。
Functor的定义图如下:
或在 nLab
https://ncatlab.org/nlab/show/functor
在这里,如您所见,F(f)
表达式在类别图中看起来很典型。
我设法在 JavaScript 中将 Array.map
实现为函子,如下所示:
const compose = f => g => x => g(f(x));
const f = a => a * 2;
const F = a => [a];
const A = 1;
const FA = F(A); //[1]
const Ff = compose(f)(F);
const FB = Ff([FA]);
console.log(FB); //[2]
F = a => [a]
当A = 1
,
F(1) = [1]
不过,虽然我明白F(f)
的意思,
F(f) = [f]
至少在 JavaScript 中不会作为函数工作。
.
其实我能想到的合适的方法就是函数组合如:
compose(f)(F)
.
我也是
FB = Ff([FA])
然而,为了让它起作用,我认为这个表达式只适用于数组,在其他情况下,事情会出错。
所以,这是我的问题。
虽然我理解 F(A)
、 F(B)
和 F(B)
的建议,但事实上 F(A)
、F(B)
有效,但 [= =12=] 必须是函数的组合不能直接套用?
或者,在范畴论中,它是否允许将 f
和 g
的函数组合表示为 g(f)
含蓄地??
要在JavaScript中组合两个函数,我可以想到三种方法。
第一种方法
最简单的方法是在第二个函数的调用中调用第一个函数。
F(f(x)) // -> result
这只需要定义两个函数并提供所需的正确参数
第二种方法
您在问题中提出的 componse
函数方式,您在其中生成一个结合了两个函数结果的函数。我会在这里稍微简化一下。
const compose = (f, g) => ((x) => (g(f(x))));
const Ff = compose(f, F);
Ff(x) // -> result exact to F(f(x))
第三种方法
此方法会回答您所需的语法 (F(f)
)。您可以声明一个特殊版本的外部函数 F
,它要么接受一个原始类型参数并立即计算结果,要么接受一个函数参数和 returns 另一个结合了两者执行的函数。您可以通过定义以下函数生成器来完成此操作 composify
.
const composify = (f) => (
(x) => {
if (x instanceof Function) {
return (z) => (f(x(z)));
}
return f(x);
}
);
const Fc = composify(F);
const fc = composify(f);
Fc(x) // -> result exact to F(x)
Fc(fc)(x) // -> result exact to F(f(x))
fc(Fc)(x) // -> result exact to f(F(x))
我知道第三种方法需要将你的数学函数定义为特殊函数,但如果你愿意这样做,你将能够使用所需的语法在两个方向上执行组合。
这是一个例子:
const composify = (f) => (
(x) => {
if (x instanceof Function) {
return (z) => (f(x(z)));
}
return f(x);
}
);
const addOne = (x) => (x + 1);
const double = (x) => (x * 2);
const composingAddOne = composify(addOne);
const composingDouble = composify(double);
console.log(composingAddOne(3)); // -> (3 + 1) = 4
console.log(composingDouble(3)); // -> (3 * 2) = 6
console.log(composingDouble(composingAddOne)(3)); // -> (3 + 1) * 2 = 8
console.log(composingAddOne(composingDouble)(3)); // -> (3 * 2) + 1 = 7
最后更新:
您实现的实际上是 (a -> b) -> a -> [b]
,但您自欺欺人地认为它是 (a -> b) -> [a] -> [b]
(详情请见下文)。
观察 Javascript,评估
[Int] * Int
会 return 支持 Int
,这可能是所有混淆的来源。
在类型设置中,F(f)
只有在您的类型系统允许类型变量像
一样“通用”时才有意义(例如在 Haskell 中)
F :: a -> [b]
其中 a
可以是 Int
和 (Int -> Int)
或任何东西,b
也是如此。而你正在寻找的可能是 a
的情况 (a0 -> b) -> a0
:
F :: (a0 -> b) -> a0 -> [b]
with b
being a0
here, where F . f
where
where F . f
where a0
(.) :: (b -> c) -> (a -> b) -> a -> c
c 为 [b]
,a 为 a0
。
注意这不同于
F0 :: (a -> b) -> [a] -> [b]
对于 List 来说是 fmap
,而您所知道的 Functor
(至少在 Haskell 中实现)只是存在一个 F
的任何类型函数
fmap :: (a -> b) -> F a -> F b
另请注意,此 F
与 F
在您的示例中作为函数存在于完全不同的抽象级别上。 (实际上在 Haskell 中你甚至不能将 F
定义为一个函数。)
另一方面,在无类型的 lambda 演算等中,只要您写得更明确,这是可能的,例如
const F = a => _.isFunction(a) ? x => [a(x)] : [a]
以上是从编程语言理论的角度。
Or, in category theory, does it allow to express function composition of f and g as just g(f) implicitly??
据我了解,范畴论是广义函数论。它不关心语法。
如果你想通过编程语言的实现来表达范畴论中的一个概念(例如仿函数),那么客观上它几乎归结为语言特性,主观上归结为语言用户。
JavaScript 数组的仿函数实现是 Array.map
,它接受数组元素上的函数并生成数组上的函数。如果 f
是某个函数,那么,就您的图表的分类语言而言,F(f)
是 .map(f)
(请原谅我滥用符号)。
在图中,恒等式和组成并不意味着应该如何实现函子抽象。相反,图表表达的是函子定律:具体来说,.map(id)
必须与 id
相同,并且 .map(f).map(g)
必须与 .map(compose(f)(g))
相同.
我这里回答了很多,都不满意,自己解决了。
根据 nLab 中的图表:
这里的X,Y,Z其实就是恒等态射
所以 X,Y,Z 和 f,g,h 的类型是相同的。
因此,我们可以一致地写F(f)
或F(X)
。
根据这个 QA 流程,虽然很多人从未提及并且不同意我最初的回应,但这似乎是一个众所周知的事实。
https://mathoverflow.net/questions/336533/why-is-an-object-not-defined-as-identity-morphism
https://ncatlab.org/nlab/show/single-sorted+definition+of+a+category
从范畴定义single-sorted来看,对象X,Y,Z是恒等态射
我尝试在 JavaScript 中实现一个 Functor。
Functor的定义图如下:
或在 nLab
https://ncatlab.org/nlab/show/functor
在这里,如您所见,F(f)
表达式在类别图中看起来很典型。
我设法在 JavaScript 中将 Array.map
实现为函子,如下所示:
const compose = f => g => x => g(f(x));
const f = a => a * 2;
const F = a => [a];
const A = 1;
const FA = F(A); //[1]
const Ff = compose(f)(F);
const FB = Ff([FA]);
console.log(FB); //[2]
F = a => [a]
当A = 1
,
F(1) = [1]
不过,虽然我明白F(f)
的意思,
F(f) = [f]
至少在 JavaScript 中不会作为函数工作。 .
其实我能想到的合适的方法就是函数组合如:
compose(f)(F)
.
我也是
FB = Ff([FA])
然而,为了让它起作用,我认为这个表达式只适用于数组,在其他情况下,事情会出错。
所以,这是我的问题。
虽然我理解 F(A)
、 F(B)
和 F(B)
的建议,但事实上 F(A)
、F(B)
有效,但 [= =12=] 必须是函数的组合不能直接套用?
或者,在范畴论中,它是否允许将 f
和 g
的函数组合表示为 g(f)
含蓄地??
要在JavaScript中组合两个函数,我可以想到三种方法。
第一种方法
最简单的方法是在第二个函数的调用中调用第一个函数。
F(f(x)) // -> result
这只需要定义两个函数并提供所需的正确参数
第二种方法
您在问题中提出的 componse
函数方式,您在其中生成一个结合了两个函数结果的函数。我会在这里稍微简化一下。
const compose = (f, g) => ((x) => (g(f(x))));
const Ff = compose(f, F);
Ff(x) // -> result exact to F(f(x))
第三种方法
此方法会回答您所需的语法 (F(f)
)。您可以声明一个特殊版本的外部函数 F
,它要么接受一个原始类型参数并立即计算结果,要么接受一个函数参数和 returns 另一个结合了两者执行的函数。您可以通过定义以下函数生成器来完成此操作 composify
.
const composify = (f) => (
(x) => {
if (x instanceof Function) {
return (z) => (f(x(z)));
}
return f(x);
}
);
const Fc = composify(F);
const fc = composify(f);
Fc(x) // -> result exact to F(x)
Fc(fc)(x) // -> result exact to F(f(x))
fc(Fc)(x) // -> result exact to f(F(x))
我知道第三种方法需要将你的数学函数定义为特殊函数,但如果你愿意这样做,你将能够使用所需的语法在两个方向上执行组合。
这是一个例子:
const composify = (f) => (
(x) => {
if (x instanceof Function) {
return (z) => (f(x(z)));
}
return f(x);
}
);
const addOne = (x) => (x + 1);
const double = (x) => (x * 2);
const composingAddOne = composify(addOne);
const composingDouble = composify(double);
console.log(composingAddOne(3)); // -> (3 + 1) = 4
console.log(composingDouble(3)); // -> (3 * 2) = 6
console.log(composingDouble(composingAddOne)(3)); // -> (3 + 1) * 2 = 8
console.log(composingAddOne(composingDouble)(3)); // -> (3 * 2) + 1 = 7
最后更新:
您实现的实际上是 (a -> b) -> a -> [b]
,但您自欺欺人地认为它是 (a -> b) -> [a] -> [b]
(详情请见下文)。
观察 Javascript,评估
[Int] * Int
会 return 支持 Int
,这可能是所有混淆的来源。
在类型设置中,F(f)
只有在您的类型系统允许类型变量像
F :: a -> [b]
其中 a
可以是 Int
和 (Int -> Int)
或任何东西,b
也是如此。而你正在寻找的可能是 a
的情况 (a0 -> b) -> a0
:
F :: (a0 -> b) -> a0 -> [b]
with b
being a0
here, where F . f
where
F . f
where a0
(.) :: (b -> c) -> (a -> b) -> a -> c
c 为 [b]
,a 为 a0
。
注意这不同于
F0 :: (a -> b) -> [a] -> [b]
对于 List 来说是 fmap
,而您所知道的 Functor
(至少在 Haskell 中实现)只是存在一个 F
的任何类型函数
fmap :: (a -> b) -> F a -> F b
另请注意,此 F
与 F
在您的示例中作为函数存在于完全不同的抽象级别上。 (实际上在 Haskell 中你甚至不能将 F
定义为一个函数。)
另一方面,在无类型的 lambda 演算等中,只要您写得更明确,这是可能的,例如
const F = a => _.isFunction(a) ? x => [a(x)] : [a]
以上是从编程语言理论的角度。
Or, in category theory, does it allow to express function composition of f and g as just g(f) implicitly??
据我了解,范畴论是广义函数论。它不关心语法。
如果你想通过编程语言的实现来表达范畴论中的一个概念(例如仿函数),那么客观上它几乎归结为语言特性,主观上归结为语言用户。
JavaScript 数组的仿函数实现是 Array.map
,它接受数组元素上的函数并生成数组上的函数。如果 f
是某个函数,那么,就您的图表的分类语言而言,F(f)
是 .map(f)
(请原谅我滥用符号)。
在图中,恒等式和组成并不意味着应该如何实现函子抽象。相反,图表表达的是函子定律:具体来说,.map(id)
必须与 id
相同,并且 .map(f).map(g)
必须与 .map(compose(f)(g))
相同.
我这里回答了很多,都不满意,自己解决了。
根据 nLab 中的图表:
这里的X,Y,Z其实就是恒等态射
所以 X,Y,Z 和 f,g,h 的类型是相同的。
因此,我们可以一致地写F(f)
或F(X)
。
根据这个 QA 流程,虽然很多人从未提及并且不同意我最初的回应,但这似乎是一个众所周知的事实。
https://mathoverflow.net/questions/336533/why-is-an-object-not-defined-as-identity-morphism
https://ncatlab.org/nlab/show/single-sorted+definition+of+a+category
从范畴定义single-sorted来看,对象X,Y,Z是恒等态射