簡體   English   中英

Vim 腳本中的“reduce”函數

[英]A “reduce” function in Vim script

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

在哈斯克爾:

foldl (+) 0 [1..5]
15

在 J:

+/>:i.5
15

在 Vim 腳本中:...?

為了將來參考,這里是我的主題變體,靈感來自@MatthewStrawbridge 鏈接的答案。

原始示例問題的表達式:

eval(join(range(1, 5), '+'))

一個更通用的解決方案,使用Add() ,其中arange(1, 5)

eval(repeat('Add(',len(a)-1).a[0].','.join(a[1:],'),').')')

這構造了字符串"Add(Add(Add(Add(1,2),3),4),5)" ,然后eval s 它。 樂趣!

最后是Reduce() ,它接受一個 Funcref 和一個列表,然后使用 Vim 的列表“解構”語法[x, y; z] [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

我認為您應該構造一個字符串然后執行它(我承認這感覺有點笨拙)。 幫助( :h E714 )給出了這個例子:

:exe 'let sum = ' . join(nrlist, '+')

因此,在您的情況下, nrlist[1, 2, 3, 4, 5] ,它將構造字符串let sum = 1+2+3+4+5然后執行它。

或者,您可以編寫自己的 reduce 函數,因為沒有內置的。

編輯:

我在 vim_use Google Group 上找到了關於Vim 中函數式編程的討論vim 中的語言構建與 emacs 中的語言構建相比有多強大? ,2010 年 1 月 25 日),其中包括一些這樣的 reduce 函數的實現。

第一個,由湯姆鏈接,如下:

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)

遺憾的是它沒有減少功能,這是我的

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 定義的 sum 函數

let Sum = {... -> s:reduce(0, {acc, arg -> acc + arg}, a:000)}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM