Functional programming A「;减少;Vim脚本中的函数

Functional programming A「;减少;Vim脚本中的函数,functional-programming,vim,Functional Programming,Vim,Vim脚本有一些非常基本的函数编程工具 它有map()和filter(),但据我所知,它缺少reduce()函数。“”将值集合减少为单个值 有没有办法创建reduce()或在Vim脚本中模拟它?在Vim脚本表达式中,是否可以在不编写显式循环的情况下减少值列表?举个例子,在加法运算中有没有减少前五个正整数的方法,就像函数语言的过程一样? 在JavaScript中: [1, 2, 3, 4, 5].reduce(function(x, y) { return x + y; }); 15 在Cloj

Vim脚本有一些非常基本的函数编程工具

它有
map()
filter()
,但据我所知,它缺少
reduce()
函数。“”将值集合减少为单个值

有没有办法创建
reduce()
或在Vim脚本中模拟它?在Vim脚本表达式中,是否可以在不编写显式循环的情况下减少值列表?举个例子,在加法运算中有没有减少前五个正整数的方法,就像函数语言的过程一样?

在JavaScript中:

[1, 2, 3, 4, 5].reduce(function(x, y) { return x + y; });
15
在Clojure中:

(reduce + (range 1 (inc 5)))
15
在哈斯克尔:

foldl (+) 0 [1..5]
15
在J中:


在Vim脚本中:…?

我认为您需要构造一个字符串,然后执行它(我承认这感觉有点笨拙)。帮助(
:he714
)给出了以下示例:

:exe 'let sum = ' . join(nrlist, '+')
因此,在您的例子中,
nrlist
[1,2,3,4,5]
,它将构造字符串
let sum=1+2+3+4+5
,然后执行它

或者,您也可以编写自己的reduce函数,因为没有内置函数

编辑:

我在vim_use Google Group(2010年1月25日,vim中的语言构建与emacs中的语言构建相比有多强大)上发现了关于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'))
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)
函数!减少(ffn,列表)“{{{3
如果为空(a:列表)
返回“”
其他的
让列表=复制(a:列表)
设s:acc=remove(列表,0)
设ffn=替换(a:ffn,“\”,“s:acc”,“g”)
对于列表中的val
设s:acc=eval(替换为(ffn,\',val,'g'))
外循环
返回s:acc
恩迪夫
endf
回声减少(“v:val+v:acc”[1,2,3,4])
回声减弱(“v:val>v:acc?v:val:v:acc”,[1,2,3,4])
echom Reduce(“'v:val'
第二篇由安东尼·斯克里文撰写,内容如下:

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'))
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)
fun Reduce(函数名,列表)
设F=函数(a:funcname)
设acc=a:列表[0]
对于:列表[1:]中的值
设acc=F(acc,值)
外循环
返回acc
结束
乐趣补充(a,b)
返回a:a+a:b
结束
最大乐趣(a、b)
返回a:a>a:b?a:a:a:b
结束
范敏(a,b)
返回a:a
以下是我对这个主题的一些变化,灵感来自@matthewstrobbridge链接的答案,以供将来参考

原始示例问题的表达式:

eval(join(range(1, 5), '+'))
同样,使用
Add()
,其中
A
范围(1,5)
,这是一个更通用的解决方案:

这将构造字符串“Add(Add(Add)(Add(1,2),3),4),5)”
,然后
eval
s it.Fun

最后,
Reduce()
,它获取一个Funcref和一个列表,然后使用Vim的列表“destructuring”语法
[x,y;z]
在循环中对其进行缩减。请参见
: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

很遗憾,它没有reduce函数,这是我的

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)}

非常好的信息,谢谢。你甚至在:帮助中找到了一个例子,我没有看到。做得好!@matthewstrobbridge代替
执行'let var='。expr
我真的建议使用
let var=eval(expr)
。另外请注意,这两个函数都有弱点:2.第二次使用
let F=function(a:funcname)
。虽然我确实需要传递函数引用以减少实现,但缺点是一旦定义函数
F
(使用
:function F()…endfunction
命令),此命令将抛出错误(变量名与现有函数冲突)。解决方法是使用
let d={}let d.F=函数(a:funcname)
.1.第一次使用
s:acc
是因为未知的原因:just
acc
应该也能正常工作。尽管缺点是构造递归(reduce表达式中的reduce调用)存在问题。在这样的实现中,我永远不会使用
v:…
变量,我只会使用
(即局部变量)并且没有
substitute()
,因为它会破坏所有
v:acc
字符串,无论它们是否实际引用变量(字符串中可能有
v:acc
)。另外,在reduce表达式中使用
s:v
也不明显,因为
s:v
将在定义reduce函数的脚本上下文中进行计算。@glts因此,如果需要reduce,我建议采用第二种实现,但删除
let F
并替换
F()
with
a:func
(and
a:funcname
with
a:func
):在参数中明确要求函数引用。要使其与
sort()
一致(还包括
map()
filter()
)最好是交换<代码> a:FUNC和<代码>:列表< /COD>并添加第三个可以持有字典的可选参数。我现在看到,在学习部分VistScript VimScript的硬方法在练习部分中有这一点!“实现<代码>还原()/代码>。