JavaScript中的Functor实现 第一种方法第二种方法第三种方法

问题描述

我尝试用JavaScript实现Functor。

Functor的定义图如下:

enter image description here

或在nLab

enter image description here

https://ncatlab.org/nlab/show/functor

在这里,您看到F(f)表达式在类别图中看起来很典型。

我设法通过JavaScript将Array.map实现为Functor,如下所示:

  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)无效,{{1 }}是否必须直接组成功能?

或者,在范畴论中,它是否允许将F(f)f的功能组合表示为g 隐式地??

解决方法

最新更新:

您实现的实际上是(a -> b) -> a -> [b],但是您欺骗自己以为它是(a -> b) -> [a] -> [b](有关更多详细信息,请参见下文)。

在Javascript中进行观察,评估

[Int] * Int

将返回Int,这可能是所有混乱的起因。


在类型设置中,F(f)仅在类型系统允许类型变量像“通用”那样的情况下才有意义(例如在Haskell中)

F :: a -> [b] 

其中a可以是Int(Int -> Int)或其他任何东西,b也可以。而您正在寻找的a可能是(a0 -> b) -> a0的情况:

F :: (a0 -> b) -> a0 -> [b]

此处ba0,当您将F . f放在其中时会发生这种情况

(.) :: (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] 

以上是从编程语言理论的角度来看。


或者,在范畴论中,它是否允许将f和g的函数组成隐式表示为g(f)?

据我了解,范畴理论是一种泛泛的功能理论。它本身与语法无关。

如果您想通过一种编程语言的实现来表达范畴论中的一个概念(例如functor),那么客观地讲,它可以归结为语言功能,主观上可以归结为语言用户。

,

JavaScript数组的函子实现是Array.map,它对数组元素采用函数,对数组产生函数。如果f是某个函数,那么根据图表的分类语言,F(f).map(f)(请原谅我对符号的滥用)。

在图中,标识和组成并不表示应如何实现函子抽象。相反,这些图表示的是函子定律:具体来说,.map(id)必须与id相同,并且.map(f).map(g)必须与.map(compose(f)(g))相同

,

要在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的特殊版本,该特殊版本可以采用原始类型参数并立即计算结果,也可以采用函数参数并返回结合了两者执行的另一个函数。您可以通过定义以下函数生成器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

,

在这里有很多答案并且对它们不满意之后,我自己解决了。

根据nLab中的图表:

enter image description here

这里,X,Y,Z实际上是同一性态。

所以X,Y,Z和f,g,h的类型相同。

因此,我们可以一致地写F(f)F(X)

根据此质量检查流程,尽管许多人从未提及过,也不同意我的最初反应,但这似乎是一个已知事实。

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

从类别的单分类定义的角度来看,对象X,Y,Z是身份同态。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...