在J中实现Haskell的foldl1的最有效方法是什么?

时间:2011-03-06 04:38:29

标签: j

在Haskell中,有两个函数允许对项目列表执行操作,以便将其减少为单个值。 (当然,有两个以上,但这些是我感兴趣的两个。)它们是foldl1foldr1。如果要执行的操作是commutative(例如添加),则使用这些操作无关紧要。结果将是相同的。但是,如果操作可交换(例如,减法),则两者产生非常不同的结果。例如:

foldr1 (-) [1..9]
foldl1 (-) [1..9]

第一个答案是5,第二个答案是-43。等效于foldr1的J是插入副词/,例如,

-/ 1+i.9

相当于foldr1 (-) [1..9]。我想在J中创建一个类似于插入副词的副词,但是向左折叠而不是向右折叠。我能想到的最好的是:

foldl =: 1 : 'u~/@|.'

因此,可以说:

- foldl 1+i.9

并得到-43作为答案,这是从左侧折叠中得到的结果。

在J中有更好的方法吗?出于某种原因,反转y论证对我来说似乎并不合适。也许有一种方法可以做到这一点,而不必诉诸于此。

2 个答案:

答案 0 :(得分:3)

我认为没有比你描述的更好的折叠方式:

(v~) / (|. list)

这是一种非常自然的方式,几乎是“字面上”的定义实现。逆转清单的成本非常小(imo)。

实现左侧折叠的另一种显而易见的方法是设置

new_list = (first v second) v rest

例如:

foldl_once =: 1 :'(u / 0 1 { y), (2}. y)'
foldl =: 1 :'(u foldl_once)^:(<:#y) y'

这样:

- foldl >:i.9
_43

但是你的方式在空间和时间上都比更好

答案 1 :(得分:1)

   ($:@}:-{:)^:(1<#) 1+i.9
_43

不知道它是否更高(或更低)效率。