Vim脚本有一些非常基本的函数编程工具。
它有map()
和filter()
,但据我所知,它缺少reduce()
功能。 “Reduce”会将值集合减少为单个值。
有没有办法在Vim脚本中创建reduce()
或以某种方式模拟它?是否可以在Vim脚本表达式中减少值列表而不编写显式循环?举个例子,有没有办法减少加法运算的前五个正整数,这与函数式语言的课程相同?
在JavaScript中:
[1, 2, 3, 4, 5].reduce(function(x, y) { return x + y; });
15
在Clojure中:
(reduce + (range 1 (inc 5)))
15
在Haskell:
foldl (+) 0 [1..5]
15
在J:
+/>:i.5
15
在Vim脚本中:...?
答案 0 :(得分:6)
为了将来参考,以下是我对主题的各种变化,受到@MatthewStrawbridge链接的答案的启发。
原始示例问题的表达式:
eval(join(range(1, 5), '+'))
使用Add()
,a
range(1, 5)
为eval(repeat('Add(',len(a)-1).a[0].','.join(a[1:],'),').')')
的同一静脉的更一般解决方案:
"Add(Add(Add(Add(1,2),3),4),5)"
这构造了字符串eval
,然后构建了Reduce()
。有趣!
最后,[x, y; z]
,它接受一个Funcref和一个列表,然后使用Vim的列表“destructuring”语法:h :let-unpack
在循环中减少它。请参阅function! Reduce(f, list)
let [acc; tail] = a:list
while !empty(tail)
let [head; tail] = tail
let acc = a:f(acc, head)
endwhile
return acc
endfunction
。
:echo Reduce(function('Add'), range(1, 5))
15
这就是它的用法:
{{1}}
答案 1 :(得分:5)
我认为你应该构造一个字符串,然后执行它(我承认感觉有点笨重)。帮助(:h E714
)给出了这个例子:
:exe 'let sum = ' . join(nrlist, '+')
所以在你的情况下,nrlist
是[1, 2, 3, 4, 5]
,它会构造字符串let sum = 1+2+3+4+5
,然后执行它。
或者,您可以编写自己的reduce函数,因为没有内置的函数。
修改强>
我在vim_use Google群组中找到了a discussion( vim中的语言构建功能与emacs中的语言构建相比有多强大?,2010年1月25日)关于Vim中的函数式编程包括几个这样的reduce函数的实现。
第一个是Tom Link,如下:
function! Reduce(ffn, list) "{{{3
if empty(a:list)
return ''
else
let list = copy(a:list)
let s:acc = remove(list, 0)
let ffn = substitute(a:ffn, '\<v:acc\>', "s:acc", 'g')
for val in list
let s:acc = eval(substitute(ffn, '\<v:val\>', val, 'g'))
endfor
return s:acc
endif
endf
echom Reduce("v:val + v:acc", [1, 2, 3, 4])
echom Reduce("v:val > v:acc ? v:val : v:acc", [1, 2, 3, 4])
echom Reduce("'v:val' < v:acc ? 'v:val' : v:acc", split("characters",
'\zs'))
第二部分,Antony Scriven,如下:
fun Reduce(funcname, list)
let F = function(a:funcname)
let acc = a:list[0]
for value in a:list[1:]
let acc = F(acc, value)
endfor
return acc
endfun
fun Add(a,b)
return a:a + a:b
endfun
fun Max(a,b)
return a:a > a:b ? a:a : a:b
endfun
fun Min(a,b)
return a:a < a:b ? a:a : a:b
endfun
let list = [1,2,3,4,5]
echo Reduce('Add', list)
echo Reduce('Max', list)
echo Reduce('Min', list)
答案 2 :(得分:0)
遗憾的是它没有减少功能,这是我的
function s:reduce(acc, fn, args) abort
let acc = a:acc
for item in a:args
let acc = a:fn(a:acc, item)
endfor
return acc
endfunc
这里是根据reduce定义的求和函数
let Sum = {... -> s:reduce(0, {acc, arg -> acc + arg}, a:000)}