Hi list.

I know there was some discussions or implementation of lambda() from before. 
However, because the necessity is not clear, the discussions was stopped . I 
hope to make it clear here.
Currently, we have two or three functions which is taking an argument to handle 
items

* sort
* map
* filter

map() take an expr as value to replace items. filter() take an expr as a 
condition to remain items. We can call them in one liner. And it's verrrrrry 
useful.

:echo map([10, 35, 24], 'v:val . "%"')
=> ['10%', '35%', '24%']

:echo filter([10, 35, 24], 'v:val < 30')
=> [10, 24]

But sort() is not good. we must have user-defined-function to compare items.
And I have frustration to call sort().

See: 
https://groups.google.com/forum/#!searchin/vim_dev/sort$20lambda/vim_dev/32Wk542f_cs/e4uyhYw_jO4J

I suggested that sort() should take an expr string as a condition (or funcref). 
But discussion was stopped.
Maybe, most of users want to use expr as condition like below:

:echo sort([10,35,24], 'a:lhs - a:rhs')

However, vim had already decided to take second argument as funcref or function 
name. Many programming languages have lambda()/clojure() to solve this problem.
As you know, user-defined-function that called by sort() can't capture local 
variables in the scope.

function! s:compare(lhs, rhs)
  " want to refer x in s:foo
endfunction
function! s:foo(arr)
  let x = 1
  return sort(a:arr, function('s:compare'))
endfunction

If "s:compare" is defined outer of the running script, it can't references the 
variables at least.

* I don't want to write s:complare function just for sort().
* I don't want to write Upper-case variable name to take funcref.
* I don't want to call delfunction for needless-function.

So I decided to implement lambda() function. This lambda()'s usage is below.

:let F = lambda('return a:1 + a:2')
:echo F(1, 2)
=> 3

This lambda() is possible to capture the local scope variables.

function! s:foo(y)
  let x = 1
  return lambda('return x + a:y + a:1')
endfunction
echo s:foo(1)(2)
=> 4

This lambda() can be taken also for map/filter.

:echo map([1, 2, 3], lambda("return a:1 + 1"))
=> [2, 3, 4]

:echo filter([1, 2, 3], lambda("return a:1 + 1"))
=> [1, 2]

:echo sort([10,35,24], lambda("return a:1 - a:2")
=> [10, 24, 35]

It's beautiful because interfaces are unified.
As you noticed, this lambda() takes the statements instead of expression. Yes, 
it is possible to include several lines.

let F = lambda('
\  let x = 1
\  return a:1 + x
\')
echo F(2)
=> 3

A function that is generated by lambda() have a scope. So you can make 
auto-increment counter function very easily without tainting s: scope.

function! s:counter(x)
  let x = a:x
  return lambda("
  \ let x += 1 \n
  \ return x
  \")
endfunction
let F = s:counter(0)
echo F()
=> 1
echo F()
=> 2
echo F()
=> 3

A function object that is generated by lambda() is managed by GC. So if 
reference are removed, it will be corrected/deleted by next GC. Currently, 
lambda() is sandboxed function. But if it's not required, I'll remove the check.

This's patch include

* implementation
* tests
* doc (Sorry it's not good english)

https://gist.github.com/mattn/50fa1dc854911d5cb797

How about this?

- Yasuhiro Matsumoto

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui