如何实现一个仿函数,使 map 可以应用于两个函数?
How to implement a functor so that map can be applied to two functions?
在Haskell中可以对两个函数应用fmap
,这基本上就是函数组合。您甚至可以组合 fmap
以启用具有更高元数 (fmap . fmap
) 的函数组合。
这是可行的,因为函数是函子。
如何在 Javascript 中实现这样的仿函数(或适当的 map
方法)?
这是我目前尝试过的方法:
funcProto = {
map(f) { return y => f(this.x(y)) }
};
function func(x) {
return Object.assign(Object.create(funcProto), {x: x});
}
const comp = f => g => x => f(g(x));
const map = f => ftor => ftor.map(f);
const sub = y => x => x - y;
const sqr = x => x * x;
const inc = x => x + 1;
这适用于正常的函数组合:
func(sqr).map(inc)(2); // 5
但是,它不适用于 map
的组合版本:
const map2 = comp(map)(map);
map2(sub)(sub)(10)(5)(4); // Error
我认为我太适应了 Javascript 中仿函数的传统实现方式。作为仿函数的函数与 list 或 maybe 的行为不同。
在Haskell中,一切都是函数。在你的 javascript 中,你的一些函数被表示为带有 .x()
方法的 func
s,还有一些是原生的 Function
s。那不行。
以下是三种方法:
const sub = y => x => x - y;
const sqr = x => x * x;
const inc = x => x + 1;
const comp = f => g => x => f(g(x));
纯函数,无方法。
const fmap = comp; // for functions only
console.log(fmap(inc)(sqr)(1)) // 5
const fmap2 = comp(fmap)(fmap);
console.log(fmap2(sub)(sub)(10)(5)(4)); // 9
扩展本机 Function
s,使用 fmap
作为方法:
Function.prototype.fmap = function(f) { return comp(this)(f); };
console.log(sqr.fmap(inc)(1)); // 5
const fmap2 = comp.fmap(comp) // not exactly what you want, works just like above
Function.prototype.fmap2 = function(f) { return this.fmap(g => g.fmap(f)); } // better
console.log(sub.fmap2(sub)(10)(5)(4)); // 9
构建您自己的函数类型(也在 ES6 中):
function Func(f) {
if (!new.target) return new Func(f);
this.call = f;
}
// Ahem.
const sub = Func(y => Func(x => x - y));
const sqr = Func(x => x * x);
const inc = Func(x => x + 1);
const comp = Func(f => Func(g => Func(x => f.call(g.call(x)))));
// Now let's start
const fmap = Func(f => Func(x => x.fmap(f))); // a typeclass!
Func.prototype.fmap = function(f) { return comp(this)(f); }; // an instance of the class!
console.log(fmap.call(inc).call(sqr).call(1)); // 5
const fmap2 = comp.call(fmap).call(fmap);
console.log(fmap2.call(sub).call(sub).call(10).call(5).call(4)); // 9
如果我弄错了,请原谅我,但您似乎对 Haskell 中的 Functor
感到困惑。 Haskell中的Functor
类型class表示定义了"map"(更准确地说是fmap
)的数据类型:
https://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor.html
例如,列表(Haskell 中的[]
)是Functor
的实例,例如:
fmap (\x->x+1) [1,2,3] -- returns [2,3,4]
正如上面文档中所指定的那样,fmap (f . g)
确实应该等同于 fmap f . fmap g
(回想一下 Haskell 中的 .
表示函数组合,即, (f.g) x
等于 f(g(x))
)。例如,让
f x = x + 1
和:
g y = y * 2
然后
fmap (f.g) [1,2,3] -- equivalent to [(f.g) 1, (f.g) 2, (f.g) 3]
和
(fmap f . fmap g) [1,2,3] -- equivalent to (fmap f (fmap g [1,2,3]))
是等价的 return [3,5,7]
.
Array
在 JavaScript 中已经是 Functor
,因为它们有 map
.
const f = x => x + 1;
const g = y => y * 2;
const comp = f => g => x => f(g(x));
const fmap_array = f => a => a.map(f);
fmap_array (comp(f)(g)) ([1,2,3]); // [3,5,7]
(comp (fmap_array(f)) (fmap_array(g))) ([1,2,3]); // [3,5,7]
或者,如果您愿意,可以这样做:
Array.prototype.fmap = function(f) { return this.map(f); }
[1,2,3].fmap(f); // [2,3,4]
[1,2,3].fmap(g); // [2,4,6]
[1,2,3].fmap(comp(f)(g)); // [3,5,7]
[1,2,3].fmap(g).fmap(f); // [3,5,7]
P.S.
现在我明白你在问题中的意思了——函数(Haskell中的->
)也是Functor
的一个实例,确实定义为函数组合fmap f g = (f . g)
:
https://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Base.html#line-638
对于 JavaScript、
中的类似内容
const fmap_func = f => g => comp(f)(g); // or "const fmap_func = comp;"!
fmap_func(f)(g)(42); // 85
或者,如果您愿意,可以再说一遍:
Function.prototype.fmap = function(f) { return comp(f)(this); };
g.fmap(f)(42); // 85
在Haskell中可以对两个函数应用fmap
,这基本上就是函数组合。您甚至可以组合 fmap
以启用具有更高元数 (fmap . fmap
) 的函数组合。
这是可行的,因为函数是函子。
如何在 Javascript 中实现这样的仿函数(或适当的 map
方法)?
这是我目前尝试过的方法:
funcProto = {
map(f) { return y => f(this.x(y)) }
};
function func(x) {
return Object.assign(Object.create(funcProto), {x: x});
}
const comp = f => g => x => f(g(x));
const map = f => ftor => ftor.map(f);
const sub = y => x => x - y;
const sqr = x => x * x;
const inc = x => x + 1;
这适用于正常的函数组合:
func(sqr).map(inc)(2); // 5
但是,它不适用于 map
的组合版本:
const map2 = comp(map)(map);
map2(sub)(sub)(10)(5)(4); // Error
我认为我太适应了 Javascript 中仿函数的传统实现方式。作为仿函数的函数与 list 或 maybe 的行为不同。
在Haskell中,一切都是函数。在你的 javascript 中,你的一些函数被表示为带有 .x()
方法的 func
s,还有一些是原生的 Function
s。那不行。
以下是三种方法:
const sub = y => x => x - y;
const sqr = x => x * x;
const inc = x => x + 1;
const comp = f => g => x => f(g(x));
纯函数,无方法。
const fmap = comp; // for functions only console.log(fmap(inc)(sqr)(1)) // 5 const fmap2 = comp(fmap)(fmap); console.log(fmap2(sub)(sub)(10)(5)(4)); // 9
扩展本机
Function
s,使用fmap
作为方法:Function.prototype.fmap = function(f) { return comp(this)(f); }; console.log(sqr.fmap(inc)(1)); // 5 const fmap2 = comp.fmap(comp) // not exactly what you want, works just like above Function.prototype.fmap2 = function(f) { return this.fmap(g => g.fmap(f)); } // better console.log(sub.fmap2(sub)(10)(5)(4)); // 9
构建您自己的函数类型(也在 ES6 中):
function Func(f) { if (!new.target) return new Func(f); this.call = f; } // Ahem. const sub = Func(y => Func(x => x - y)); const sqr = Func(x => x * x); const inc = Func(x => x + 1); const comp = Func(f => Func(g => Func(x => f.call(g.call(x))))); // Now let's start const fmap = Func(f => Func(x => x.fmap(f))); // a typeclass! Func.prototype.fmap = function(f) { return comp(this)(f); }; // an instance of the class! console.log(fmap.call(inc).call(sqr).call(1)); // 5 const fmap2 = comp.call(fmap).call(fmap); console.log(fmap2.call(sub).call(sub).call(10).call(5).call(4)); // 9
如果我弄错了,请原谅我,但您似乎对 Haskell 中的 Functor
感到困惑。 Haskell中的Functor
类型class表示定义了"map"(更准确地说是fmap
)的数据类型:
https://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor.html
例如,列表(Haskell 中的[]
)是Functor
的实例,例如:
fmap (\x->x+1) [1,2,3] -- returns [2,3,4]
正如上面文档中所指定的那样,fmap (f . g)
确实应该等同于 fmap f . fmap g
(回想一下 Haskell 中的 .
表示函数组合,即, (f.g) x
等于 f(g(x))
)。例如,让
f x = x + 1
和:
g y = y * 2
然后
fmap (f.g) [1,2,3] -- equivalent to [(f.g) 1, (f.g) 2, (f.g) 3]
和
(fmap f . fmap g) [1,2,3] -- equivalent to (fmap f (fmap g [1,2,3]))
是等价的 return [3,5,7]
.
Array
在 JavaScript 中已经是 Functor
,因为它们有 map
.
const f = x => x + 1;
const g = y => y * 2;
const comp = f => g => x => f(g(x));
const fmap_array = f => a => a.map(f);
fmap_array (comp(f)(g)) ([1,2,3]); // [3,5,7]
(comp (fmap_array(f)) (fmap_array(g))) ([1,2,3]); // [3,5,7]
或者,如果您愿意,可以这样做:
Array.prototype.fmap = function(f) { return this.map(f); }
[1,2,3].fmap(f); // [2,3,4]
[1,2,3].fmap(g); // [2,4,6]
[1,2,3].fmap(comp(f)(g)); // [3,5,7]
[1,2,3].fmap(g).fmap(f); // [3,5,7]
P.S.
现在我明白你在问题中的意思了——函数(Haskell中的->
)也是Functor
的一个实例,确实定义为函数组合fmap f g = (f . g)
:
https://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Base.html#line-638
对于 JavaScript、
中的类似内容 const fmap_func = f => g => comp(f)(g); // or "const fmap_func = comp;"!
fmap_func(f)(g)(42); // 85
或者,如果您愿意,可以再说一遍:
Function.prototype.fmap = function(f) { return comp(f)(this); };
g.fmap(f)(42); // 85