在Haskell中,有两个函数允许一个对项列表执行操作,以便将其减少为单个值.(当然,有两个以上,但这些是我感兴趣的两个.)他们是foldl1
和foldr1
.如果要执行的操作是可交换的(例如添加),则使用这些操作无关紧要.结果将是相同的.但是,如果操作不是可交换的(例如,减法),则两者产生非常不同的结果.例如:
foldr1 (-) [1..9]
foldl1 (-) [1..9]
Run Code Online (Sandbox Code Playgroud)
第一个答案是5,第二个答案是-43.J等价物foldr1
是插入副词/
,例如,
-/ 1+i.9
Run Code Online (Sandbox Code Playgroud)
这相当于foldr1 (-) [1..9]
.我想在J中创建一个类似于插入副词的副词,但是向左折叠而不是向右折叠.我能想到的最好的是以下内容:
foldl =: 1 : 'u~/@|.'
Run Code Online (Sandbox Code Playgroud)
因此,可以说:
- foldl 1+i.9
Run Code Online (Sandbox Code Playgroud)
并得到-43作为答案,这是左折的预期.
在J中有更好的方法吗?出于某种原因,扭转这一y
论点对我来说似乎并不高效.也许有一种方法可以做到这一点,而不必诉诸于此.
我认为没有比您描述的更好的向左折叠方法:
(v~) / (|. list)
Run Code Online (Sandbox Code Playgroud)
这是一种非常自然的方式,几乎是定义的“字面”实现。反转列表的成本非常小(imo)。
实现左折叠的另一个明显方法是设置
new_list = (first v second) v rest
Run Code Online (Sandbox Code Playgroud)
例如:
foldl_once =: 1 :'(u / 0 1 { y), (2}. y)'
foldl =: 1 :'(u foldl_once)^:(<:#y) y'
Run Code Online (Sandbox Code Playgroud)
所以:
- foldl >:i.9
_43
Run Code Online (Sandbox Code Playgroud)
但你的方式无论在空间还是时间上都比这表现得好得多。