javascript – 如何存储Monoidal List功能链的数据?
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了javascript – 如何存储Monoidal List功能链的数据?,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含6731字,纯文字阅读大概需要10分钟。
内容图文
这是我先前问题的高级主题:
How to store data of a functional chain?
简短的想法是
一个简单的功能如下:
const L = a => L;
形式
L
L(1)
L(1)(2)
...
这似乎形成了一个列表,但实际数据根本没有存储,所以如果需要存储[1,2]这样的数据,那么完成任务的最聪明的做法是什么?
其中一个突出的想法来自@ user633183,我将其标记为已接受的答案(请参阅问题链接),另一个版本的curried函数也由@MatíasFidemraizer提供.
所以这里:
const L = a => {
const m = list => x => !x
? list
: m([...list, x]);
return m([])(a);
};
const list1 = (L)(1)(2)(3); //lazy : no data evaluation here
const list2 = (L)(4)(5)(6);
console.log(list1()) // now evaluated by the tail ()
console.log(list2())
我真正喜欢的是它结果是懒惰的评价.
虽然给定的方法满足我提到的,但是这个函数已经失去了外部结构,或者我必须使用mentiion:
代数结构
const L = a => L;
哪个表格列表,从根本上给了我们0700的identity element,可能还有Monoid或Magma.
留下一个正确的身份
Monoids和身份的最简单的例子之一是JavaScript中的数字和“字符串”和[数组].
0 + a === a === a + 0
1 * a === a === a * 1
在Strings中,空的quoate“”是标识元素.
"" + "Hello world" === "Hello world" === "Hello world" + ""
同样适用于[Array].
L也一样:
(L)(a) === (a) === (a)(L)
const L = a => L;
const a = L(5); // number is wrapped or "lift" to Type:L
// Similarity of String and Array
// "5" [5]
//left identity
console.log(
(L)(a) === (a) //true
);
//right identity
console.log(
(a) === (a)(L) //true
);
和明显的身份不变性:
const L = a => L;
console.log(
(L)(L) === (L) //true
);
console.log(
(L)(L)(L) === (L) //true
);
console.log(
(L)(L)(L)(L) === (L) //true
);
还有以下内容:
const L = a => L;
const a = (L)(1)(2)(3);
const b = (L)(1)(L)(2)(3)(L);
console.log(
(a) === (b) //true
);
问题
什么是最聪明或最优雅的方式(非常实用且没有突变(没有Array.push,也))来实现满足3个要求的L:
要求0 – 身份
一个简单的功能:
const L = a => L;
已经满足了我们已经看到的身份法.
要求1 – eval()方法
尽管L满足同一性定律,但是没有方法可以访问列出的/累积的数据.
(我在上一个问题中提供的答案提供了数据累积能力,但违反了身份法.)
懒惰评估似乎是正确的方法,因此提供更清晰的规范:
提供L的eval方法
const L = a => L; // needs to enhance to satisfy the requirements
const a = (L)(1)(2)(3);
const b = (L)(1)(L)(2)(3)(L);
console.log(
(a) === (b) //true
);
console.log(
(a).eval() //[1, 2, 3]
);
console.log(
(b).eval() //[1, 2, 3]
);
要求3 – Monoid联想法
除了突出的识别结构,Monoids也满足Associative law
(a * b) * c === a * b * c === a * (b * c)
这仅仅意味着“展平列表”,换句话说,该结构不包含嵌套列表.
[a,[b,c]]不好.
样品:
const L = a => L; // needs to enhance to satisfy the requirements
const a = (L)(1)(2);
const b = (L)(3)(4);
const c = (L)(99);
const ab = (a)(b);
const bc = (b)(c);
const abc1 = (ab)(c);
const abc2 = (a)(bc);
console.log(
abc1 === abc2 // true for Associative
);
console.log(
(ab).eval() //[1, 2, 3, 4]
);
console.log(
(abc1).eval() //[1, 2, 3, 4, 99]
);
console.log(
(abc2).eval() //[1, 2, 3, 4, 99]
);
这就是将L作为幺半群实现的3个要求.
对我来说,这对函数式编程来说是一个很大的挑战,实际上我已经尝试了一段时间,但是问起以前的问题,分享我自己的挑战并听取人们并阅读他们优雅的代码是非常好的做法.
谢谢.
解决方法:
镜子测试
为了使L自我意识,我们必须以某种方式标记它创建的值.这是一个通用特性,我们可以使用一对函数对其进行编码.我们设定了对行为的期望 –
is (Foo, 1) // false 1 is not a Foo
is (Foo, tag (Foo, 1)) // true tag (Foo, 1) is a Foo
下面我们实现is和tag.我们想要设计它们以便我们可以放入任何值,并且我们可以在以后可靠地确定值的标记.我们为null和undefined做了例外.
const Tag =
Symbol ()
const tag = (t, x) =>
x == null
? x
: Object.assign (x, { [Tag]: t })
const is = (t, x) =>
x == null
? false
: x[Tag] === t
const Foo = x =>
tag (Foo, x)
console.log
( is (Foo, 1) // false
, is (Foo, []) // false
, is (Foo, {}) // false
, is (Foo, x => x) // false
, is (Foo, true) // false
, is (Foo, undefined) // false
, is (Foo, null) // false
)
console.log
( is (Foo, Foo (1)) // true we can tag primitives
, is (Foo, Foo ([])) // true we can tag arrays
, is (Foo, Foo ({})) // true we can tag objects
, is (Foo, Foo (x => x)) // true we can even tag functions
, is (Foo, Foo (true)) // true and booleans too
, is (Foo, Foo (undefined)) // false but! we cannot tag undefined
, is (Foo, Foo (null)) // false or null
)
我们现在有一个函数Foo,它能够区分它产生的值. Foo变得自我意识 –
const Foo = x =>
is (Foo, x)
? x // x is already a Foo
: tag (Foo, x) // tag x as Foo
const f =
Foo (1)
Foo (f) === f // true
L意识更高
使用is和tag我们可以使List自我感知.如果给出了List-tagged值的输入,List可以根据您的设计规范进行响应.
const None =
Symbol ()
const L = init =>
{ const loop = (acc, x = None) =>
// x is empty: return the internal array
x === None
? acc
// x is a List: concat the two internal arrays and loop
: is (L, x)
? tag (L, y => loop (acc .concat (x ()), y))
// x is a value: append and loop
: tag (L, y => loop ([ ...acc, x ], y))
return loop ([], init)
}
我们使用您的测试数据进行尝试 –
const a =
L (1) (2)
const b =
L (3) (4)
const c =
L (99)
console.log
( (a) (b) (c) () // [ 1, 2, 3, 4, 99 ]
, (a (b)) (c) () // [ 1, 2, 3, 4, 99 ]
, (a) (b (c)) () // [ 1, 2, 3, 4, 99 ]
)
值得将此实现与最后一个实现进行比较 –
// previous implementation
const L = init =>
{ const loop = (acc, x) =>
x === undefined // don't use !x, read more below
? acc
: y => loop ([...acc, x], y)
return loop ([], init)
}
在我们的修订版中,为is(L,x)添加了一个新的分支,用于定义新的monoidal行为.最重要的是,包含在标记(L,…)中的任何返回值,以便以后可以将其标识为L标记的值.另一个变化是明确使用无符号;关于这方面的补充评论已经添加到这篇文章的末尾.
L值相等
为了确定L(x)和L(y)的相等性,我们面临另一个问题. JavaScript中的复合数据用对象表示,不能简单地与===运算符进行比较
console.log
( { a: 1 } === { a: 1 } ) // false
我们可以为L编写一个等式函数,也许叫做Lequal
const l1 =
L (1) (2) (3)
const l2 =
L (1) (2) (3)
const l3 =
L (0)
console.log
( Lequal (l1, l2) // true
, Lequal (l1, l3) // false
, Lequal (l2, l3) // false
)
但我不会在这篇文章中讨论如何做到这一点.如果您有兴趣,我在this Q&A中介绍了该主题.
// Hint:
const Lequal = (l1, l2) =>
arrayEqual // compare two arrays
( l1 () // get actual array of l1
, l2 () // get actual array of l2
)
标记深度
我在这里使用的标记技术是我在其他答案中使用的标记技术.它伴随着更广泛的例子here.
其他言论
不要使用!x来测试空值,因为它会为任何“falsy”x返回true.例如,如果你想列出L(1)(0)(3)…它会在1之后停止因为!0为真. Falsy值包括0,“”(空字符串),null,undefined,NaN,当然还有false本身.出于这个原因,我们使用显式无符号来更精确地识别列表何时终止.所有其他输入都附加到内部数组.
并且不要依赖像JSON.stringify这样的黑客来测试对象的相等性.结构遍历是绝对必要的.
const x = { a: 1, b: 2 }
const y = { b: 2, a: 1 }
console.log
(JSON.stringify (x) === JSON.stringify (y)) // false
console.log
(Lequal (L (x), L (y))) // should be true!
有关如何解决此问题的建议,请参阅this Q&A
内容总结
以上是互联网集市为您收集整理的javascript – 如何存储Monoidal List功能链的数据?全部内容,希望文章能够帮你解决javascript – 如何存储Monoidal List功能链的数据?所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。