zzz6519003 / blog

My blog about coding
4 stars 1 forks source link

函子和范畴(组合软件) #103

Open zzz6519003 opened 7 years ago

zzz6519003 commented 7 years ago

http://mp.weixin.qq.com/s/vw_FCdnBpWbxBxXONu0zAg

const Identity = value => ({map: fn=>Identity(fn(value))});
undefined
Identity
value => ({map: fn=>Identity(fn(value))})
const trace = x=> {console.log(x) return x;}
VM948:1 Uncaught SyntaxError: Unexpected token return
const trace = x=> {console.log(x)
return x;}
undefined
const u = Identity(2);
undefined
u
Object {map: function}
u.map(trace);
VM951:1 2
Object {map: function}map: fn=>Identity(fn(value))__proto__: Object
u.map(x=>x).map(trace);
VM951:1 2
Object {map: function}
const f = n => n + 1;
undefined
const g = n => n * 2;
undefined
const r1 = u.map(x=>f(g(x)));
undefined
const r2 = u.map(g).map(f);
undefined
r1.map(trace)
VM951:1 5
Object {map: function}
r2.map(trace)
VM951:1 5
Object {map: function}

const Identity2 = value=> ({map: fn => Identity2(fn(value)), valueOf: () => value,});
undefined
const ints = (Identity2(2) + Identity2(4))
undefined
trace(ints)
VM951:1 6
6
const hi = (Identity2('h') + Identity2('i'))
undefined
trace(hi)
VM951:1 hi
"hi"
const Identity3 = value=> ({map: fn => Identity2(fn(value)), valueOf: () => value, toString: () => `Identity($(value))`});
undefined
const Identity3 = value=> ({map: fn => Identity3(fn(value)), valueOf: () => value, toString: () => `Identity($(value))`});
VM1471:1 Uncaught SyntaxError: Identifier 'Identity3' has already been declared
    at <anonymous>:1:1
(anonymous) @ VM1471:1
const Identity4 = value=> ({map: fn => Identity4(fn(value)), valueOf: () => value, toString: () => `Identity4($(value))`,
[Symbol.iterator]: () => {
let first = true;
return ({
next: () => {
if (first) {
first = false;
return ({
done: false,
value
});
}
return ({
done: true
});
}
});
}});

const arr3 = [6,7,...Identity4(8)];
undefined
trace(arr3)
VM951:1 (3) [6, 7, 8]0: 61: 72: 8length: 3__proto__: Array(0)
(3) [6, 7, 8]0: 61: 72: 8length: 3__proto__: Array(0)
typeof trace(arr3)
VM951:1 (3) [6, 7, 8]
"object"
zzz6519003 commented 4 years ago

在 Haskell中,函子类型被定义为:

fmap :: (a -> b) -> f a -> f b 给出一个函数,该函数有一个参数 a,并返回一个 b 和一个有零到多个 a 在其中的函子:fmap 返回一个其中有零到多个 b 的盒子。f a 和 f b 位可以被读为 a 的函子和 b 的函子,意思是 f a 的盒子中有 a,f b 的盒子中有 b。

使用函子很简单 - 只要调用 map() 即可:

const f = [1, 2, 3]; f.map(double); // [2, 4, 6]

zzz6519003 commented 4 years ago

恒等 如果将恒等函数(x => x)传递给 f.map(),这里 f 是任何函子,那么结果应该等价于 f(即与 f 有相同含义):

const f = [1, 2, 3]; f.map(x => x); // [1, 2, 3]

zzz6519003 commented 4 years ago

下面我们用 JavaScript 再看看组合:

给出一个函子 F:

const F = [1, 2, 3]; 如下的语句都是等同的:

F.map(x => f(g(x)));

// 等同于...

F.map(g).map(f);

zzz6519003 commented 4 years ago

很多函数式编程术语都来自于范畴学,范畴学的精髓就是组合。范畴学是最开始很可怕,但是很简单,就像从跳水板跳下或者坐过山车一样。

zzz6519003 commented 4 years ago
// trace() 是一个让我们更容易检测内容的实用程序
const trace = x => {
  console.log(x);
  return x;
};

const u = Identity(2);

// 恒等定律
u.map(trace); // 2
u.map(x => x).map(trace); // 2

const f = n => n + 1;
const g = n => n * 2;

// 组合定律
const r1 = u.map(x => f(g(x)));
const r2 = u.map(g).map(f);

r1.map(trace); // 5
r2.map(trace); // 5
zzz6519003 commented 4 years ago

函子之所以牛叉,是有很多原因的。最重要的是,它们是一种抽象,我们可以用它们以作用于任何数据类型的方式来实现很多有用的事情。