Javascript 如何存储单项式列表函数链的数据?

Javascript 如何存储单项式列表函数链的数据?,javascript,arrays,list,math,functional-programming,Javascript,Arrays,List,Math,Functional Programming,这是我先前问题的一个高级主题: 简单的想法是 下面是一个简单的函数: const L = a => L; 形式 这似乎形成了一个列表,但实际数据根本没有存储,因此,如果需要存储数据,如[1,2],那么完成任务的最明智做法是什么 其中一个突出的想法来自@user633183,我将其标记为一个可接受的答案(参见问题链接),另外一个版本的curried函数也是由@Matías Fidemraizer提供的 下面是: const L=a=>{ 常数m=list=>x=>!x 列表 :m([…

这是我先前问题的一个高级主题:

简单的想法是

下面是一个简单的函数:

const L = a => L;
形式

这似乎形成了一个列表,但实际数据根本没有存储,因此,如果需要存储数据,如[1,2],那么完成任务的最明智做法是什么

其中一个突出的想法来自@user633183,我将其标记为一个可接受的答案(参见问题链接),另外一个版本的curried函数也是由@Matías Fidemraizer提供的

下面是:

const L=a=>{
常数m=list=>x=>!x
列表
:m([…列表,x]);
返回m([])(a);
}; 
常数列表1=(L)(1)(2)(3)//lazy:这里没有数据计算
常数列表2=(L)(4)(5)(6);
log(list1())//现在由尾部()计算

console.log(list2())
镜像测试

要使
L
自我意识,我们必须以某种方式标记它所创造的价值。这是一个通用特性,我们可以使用一对函数对其进行编码。我们设定了对行为的预期——

is (Foo, 1)            // false   1 is not a Foo
is (Foo, tag (Foo, 1)) // true    tag (Foo, 1) is a Foo
下面我们实现了
is
标记
。我们希望将它们设计为可以输入任何值,并且可以在以后可靠地确定值的标记。我们对
null
未定义的
进行例外处理

const标记=
符号()
常量标记=(t,x)=>
x==null
? x
:Object.assign(x,{[Tag]:t})
常数为=(t,x)=>
x==null
? 假的
:x[标记]==t
常量Foo=x=>
标签(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,未定义)//false
,is(Foo,null)//false
)
console.log
(is(Foo,Foo(1))//true我们可以标记原语
,is(Foo,Foo([])//true我们可以标记数组
,is(Foo,Foo({}))//true我们可以标记对象
,is(Foo,Foo(x=>x))//true我们甚至可以标记函数
,is(Foo,Foo(true))//true和booleans
,is(Foo,Foo(undefined))//false但是!我们不能标记undefined
,is(Foo,Foo(null))//false或null

)
镜像测试

要使
L
自我意识,我们必须以某种方式标记它所创造的价值。这是一个通用特性,我们可以使用一对函数对其进行编码。我们设定了对行为的预期——

is (Foo, 1)            // false   1 is not a Foo
is (Foo, tag (Foo, 1)) // true    tag (Foo, 1) is a Foo
下面我们实现了
is
标记
。我们希望将它们设计为可以输入任何值,并且可以在以后可靠地确定值的标记。我们对
null
未定义的
进行例外处理

const标记=
符号()
常量标记=(t,x)=>
x==null
? x
:Object.assign(x,{[Tag]:t})
常数为=(t,x)=>
x==null
? 假的
:x[标记]==t
常量Foo=x=>
标签(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,未定义)//false
,is(Foo,null)//false
)
console.log
(is(Foo,Foo(1))//true我们可以标记原语
,is(Foo,Foo([])//true我们可以标记数组
,is(Foo,Foo({}))//true我们可以标记对象
,is(Foo,Foo(x=>x))//true我们甚至可以标记函数
,is(Foo,Foo(true))//true和booleans
,is(Foo,Foo(undefined))//false但是!我们不能标记undefined
,is(Foo,Foo(null))//false或null
)
您的数据类型不一致! 所以,你想创建一个幺半群。考虑幺半群的结构:

类幺半群m其中
empty::m--标识元素
()::m->m->m——二进制操作
--它符合下列法律:
空x=x=x空——恒等式法则
(xy)z=x(yz)——缔合性定律

现在,考虑数据类型的结构:

(L)(a)=(a)=(a)(L)//身份法
((a)(b))(c)=(a)((b)(c))//结合律
因此,根据您的说法,标识元素是
L
,二进制操作是。然而:

(L)(1)//这应该是一个有效的表达式。
(五十) (1)!=(1) != (1) (L)//但它违反了身份法。
//(1)(L)甚至不是有效的表达式。它抛出了一个错误。因此:
((L)(1))(L)//这应该是一个有效的表达式。
((L)(1))(L)!=(五十) ((1)(L))//但它违反了缔合性定律。
问题是您将二进制操作与反向列表构造函数混为一谈:

//首先,将函数应用程序用作反向cons(又称snoc):
//反对:a->[a]->[a]
//snoc::[a]->a->[a]--参数翻转
常数xs=(L)(1)(2);//[1,2]
常数ys=(L)(3)(4);//[3,4]
//稍后,您将使用函数应用程序作为二进制运算符(又称append):
//附加::[a]->[a]->[a]
常数zs=(xs)(ys);//[1,2,3,4]
如果将函数应用程序用作
snoc
,则不能将其用于
append

snoc::[a]->a->[a]
附加::[a]->[a]->[a]
请注意,类型不匹配,但即使它们匹配,您仍然不希望一个操作完成两件事

您需要的是差异列表。 A是一个函数,它接受一个列表并在另一个列表前面加上前缀。例如:

const concat=xs=>ys=>xs.concat(ys);//这将创建一个差异列表。
常数f=concat([1,2,3]);//这是一个不同的列表。
console.log(f([]);//可以通过将其应用于空数组来获取其值。
console.log(f([4,5,6]);//您也可以将其应用于任何其他数组。
您的数据类型不一致! 所以,你想创建一个幺半群。考虑幺半群的结构:

c