Admit it, you’ve wanted this for a long time now.
Update: These two functions are now available in VimaholicsAnonymous.
VimL’s list sort() method allows the caller to provide a custom comparison function with which to sort by. Unfortunately, VimL doesn’t support anonymous functions (sometimes called lambdas), so the caller is forced to pre-write their comparator as a full-fledged function and provide its funcref to sort(). Well, that ends today. Now, VimL has anonymous function love! Check it:
This humble little snippet of code lets vimmers declare anonymous functions on the fly:
Like this:
The magic is in the Fn() call. It takes a string argument of the form:
The last statement will be implicitly returned by the anonymous function, so no need to explicitly add a return statement.
Unicorns, or what?!
What? You want more. Certainly, sir. Behold:
That lets you execute an anonymous function, like:
Any cooler and you’d need your jumper! :-D Oh, but there’s more… I’m just getting warmed up!
Just because I like you, here’s a little extra gift:
That lets you call your funcref'd anonymous function by name. Did you see what I did there? Yes, I cheated God! I named an annonymous function. Cool, eh?
So, apart from the obvious, is this really that amazing? My vote is: YES! I have plans for this technology. Here’s a sneaky hint of where I’m looking to take this:
That’s right. I want hygenic macros in VimL. And that code works in my current experiments. The notation is stolen from… clojure I believe, where #(…) executes a lambda.
The call to CompileMacros will process any macros in the surrounding expressions before sourcing the result. Just for completeness, defining macros currently looks like this:
But that will change in the next version. Using regex to parse is an abomination; I was merely proof-of-concepting here. I’ll use VimPEG instead.
Stay tuned, if bending the spoon is what you’re in to.
Update: These two functions are now available in VimaholicsAnonymous.
VimL’s list sort() method allows the caller to provide a custom comparison function with which to sort by. Unfortunately, VimL doesn’t support anonymous functions (sometimes called lambdas), so the caller is forced to pre-write their comparator as a full-fledged function and provide its funcref to sort(). Well, that ends today. Now, VimL has anonymous function love! Check it:
This humble little snippet of code lets vimmers declare anonymous functions on the fly:
let fn_idx = 0 function! Fn(fn_form) let [fn_args, fn_body] = split(a:fn_form, '\s*=>\s*') let g:fn_idx = g:fn_idx + 1 let fname = 'AnonFn_' . g:fn_idx let b_elems = split(fn_body, '|') let b_elems[-1] = 'return ' . b_elems[-1] exe 'func! ' . fname . fn_args . "\n" \. join(b_elems, "\n") . "\n" \. 'endfunc' return function(fname) endfunction |
Like this:
let x = ["one","two","three","four","five","six","seven","eight","nine","ten"] echo sort(x, Fn('(a, b) => len(a:a) > len(a:b)')) |
The magic is in the Fn() call. It takes a string argument of the form:
(arguments) => function-body statements separated by | (pipe)
The last statement will be implicitly returned by the anonymous function, so no need to explicitly add a return statement.
Unicorns, or what?!
What? You want more. Certainly, sir. Behold:
function! Fx(fn, ...) return call(a:fn, a:000) endfunction |
That lets you execute an anonymous function, like:
echo '2 ^ 6 = ' . string(Fx(Fn('(a, b) => pow(a:a, a:b)'), 2, 6)) |
Any cooler and you’d need your jumper! :-D Oh, but there’s more… I’m just getting warmed up!
Just because I like you, here’s a little extra gift:
let Mul = Fn('(a,b)=>let x = a:a | let y=a:b | x*y') echo '5 * 6 = ' . Fx(Mul, 5, 6) |
That lets you call your funcref'd anonymous function by name. Did you see what I did there? Yes, I cheated God! I named an annonymous function. Cool, eh?
So, apart from the obvious, is this really that amazing? My vote is: YES! I have plans for this technology. Here’s a sneaky hint of where I’m looking to take this:
CompileMacros Mul = ((a,b) => let x = a:a | let y=a:b | x*y) echo '5 * 6 = ' . #(Mul, 5, 6) echo '2 * 6 = ' . #(((a, b) => a:a * a:b), 2, 6) |
That’s right. I want hygenic macros in VimL. And that code works in my current experiments. The notation is stolen from… clojure I believe, where #(…) executes a lambda.
The call to CompileMacros will process any macros in the surrounding expressions before sourcing the result. Just for completeness, defining macros currently looks like this:
call Macro('(\+\((.\{-})\s*=>.\{-}\))', "Fn('\\1')") call Macro('\%(\n\|^\)\@<=\s*\(\w\+\)\s*=\s*\(Fn(.*=>.\{-})\)\s*\n', \ "let \\1 = \\2\n" ) call Macro('#(\(.*\))\n', "Fx(\\1)\n") call Macro('#Fn(\(.\{-}\))\n', "Fx(Fn(\\1)\n") |
But that will change in the next version. Using regex to parse is an abomination; I was merely proof-of-concepting here. I’ll use VimPEG instead.
Stay tuned, if bending the spoon is what you’re in to.
No comments:
Post a Comment