Vim script doesn't have lambda as a language feature, but you can fake similar thing with the following tricks.
When you want to pass a procedure with variables into a function in Vim script, how do you achieve it?
Let me explain with other language first, show a well-known function map
.
Ruby(*1):
a = 10
p [1, 2, 3].map {|i| i + a }
#=> [11, 12, 13]
Python:
a = 10
print map(lambda x: x + a, [1, 2, 3])
#=> [11, 12, 13]
or more strictly
a = 10
def f(x):
return x + a
print map(f, [1, 2, 3])
#=> [11, 12, 13]
On the other hand, Vim script doesn't have such fancy feature but have normal function and dictionary function. The former is like just a global function, scoped globally or file. The latter is like a method which has the concept of this
of self
in other languages.
let obj = {'a': 10}
function! obj.f(x)
return a:x + self.a
endfunction
echo obj.f(1)
"=> 11
Note that the prefix a:
means the identifier is an argument of the function.
This feature is compatible with lexical scope lambda except for the aspect of the anonymity. But it is very inconvenient that you always have to declare which variables the dictionary function will use.
The solution is to use a special variable l:
.
function! Main()
let a = 10
let obj = copy(l:)
function! obj.f(x)
return a:x + self.a
endfunction
echo obj.f(1)
endfunction
call Main()
There are three notes for using this trick:
l:
is only available in a function.- it can cause SEGV if you forget writing
copy
a:
as well if you use not only local variables
Acknowledge
thinca and tyru taught me this trick for my problem presentation. thinca is using a kind of this trick in his product.
Footnote
The following code also works on Ruby.
a = 10
f = ->(x) { x + 1 }
p [1, 2, 3].map(&f)
How about real closures? :-)
ReplyDeletefunction! Main()
lua << EOLUA
local a = 10
local f = function (x)
return a
end
vim.command('echo "' .. f() .. '"')
EOLUA
endfunction
call Main()
greetings!
if_*** is always good if I can assume everyone has it :)
ReplyDeleteif_gauche also has real closures