2016-07-03 0:27 GMT+03:00 Bram Moolenaar <[email protected]>:
>
> Ken Takata wrote:
>
>> 2016/5/27 Fri 22:38:34 UTC+9 Ken Takata wrote:
>> > Hi mattn,
>> >
>> > 2016/4/18 Mon 0:30:19 UTC+9 mattn wrote:
>> > > Hi, Bram and list.
>> > >
>> > > Updated lambda patch to be applied for latest code.
>> > >
>> > > https://gist.github.com/mattn/5bc8ded21e1033c9c0ea8cd5ecbbce11
>> > >
>> > > This include examples for timer on help file. I'm thinking lambda() have 
>> > > cooperative to work with job/timer/channel.
>> > >
>> > > So I hope to add this into vim8. How do you think?
>> > >
>> > > Thanks to k-takata, haya14busa, and all of members on vim-jp.
>> >
>> > I have tested the lambda patch with the latest Vim and I found two 
>> > problems.
>> >
>> >   1. garbagecollect_for_testing() was renamed.
>> >   2. Test_lambda_with_timer() fails on Cygwin. It seems that we need 
>> > margins
>> >      as we do in test_timers.vim.
>> >
>> > Please check attached patch.
>> >
>> > I hope that the lambda patch will be merged in Vim 8.0.
>> > This makes filter(), map() and sort() easy to use.
>> > It also works nicely with job/channel/timer features.
>>
>> I have merged my patch into your patch, and also fixed that the function
>> declaration was not sorted in alphabetical order.
>> Please check the attached patch.
>
> I have mixed feelings about this implementation.  This needs more
> thoughts and discussion.
>
>
> One of the problems with the current use of a string for an expression,
> as it's passed to map(), filter(), etc., is that this is a string, which
> requires taking care of quotes.
>
> Using lambda() for that doesn't have an advantage, it's only longer:
>
>         :call map(mylist, '"> " . v:val . " <"')
>         :call map(mylist, lambda('"> " . v:val . " <"'))
>
> Perhaps we can define the lambda not as a function call, but as an
> operator.  Then it will be parsed differently and we don't need to put
> the expression in quotes.  We do want to be able to define it inline, as
> a function argument.  We do need something around it, so that it's clear
> where the end is.  Using {} would work, it's similar to a statement
> block in most languages.
>
> We would also like to specify arguments.  We could separate the
> arguments from the statements with a "gives" symbol.  That could be ->.
> This avoid the strange use of v:val and v:key to pass values to the
> expression, like map() does.
>
>         call Func(arg, lambda{v -> return v * 3.12})
>
> That way we can do this:
>         call map(mylist, lambda{v -> return "> " . v . " <"})
>
> In most cases only one statement is needed, but having a few more should
> be possible.  Using | to separate statements hopefully works:
>
>         call Func(arg, lambda{ v -> if v < 0 | return v * 3.12 | else | 
> return v * -3.12 | endif})
>
> Something like that.  If it gets too long it's better to just define a
> function.

`lambda{ v -> if v < 0 | return v * 3.12 | else | return v * -3.12 |
endif}` is too verbose. AFAIR I already suggested lambdas
implementation once and it was just

    \arg1, arg2 : expr1

. I.e. lambda functions do *not* allow to use commands, only
expressions. Documentation for my attempt was

|  +lambda                                                      *expr-lambda*
|  +------
|  +\arg1, ...: expr1   lambda function
|  +
|  +Lambda functions are the lightweight variant of |user-functions|.
Differences
|  +between them are:
|  +
|  +1. Body of the lambda function is an |expr1| and not a sequence of |Ex|
|  +   commands.
|  +2. Lambda function does not have its own scope dictionary. It does
have scope
|  +   dictionary for |a:var| though. |l:| scope dictionary is
inherited from the
|  +   place where lambda was defined (thus it is either |g:| scope
dictionary or
|  +   |l:| dictionary of the function that defined the lambda).
|  +   You see, it is poor man closure.
|  +3. If |a:var| is not found in lambda own scope dictionary it is searched in
|  +   |a:| scope dictionary of the function where lambda was defined (if any).
|  +   This does not apply to |a:000|, |a:0|, |a:1|, ... variables.
|  +4. There are no dictionary lambdas.
|  +5. Lambda is not globally recorded anywhere like |anonymous-function|.
|  +
|  +NOTE: lambda function records the whole scope dictionary in its
body and also
|  +      |a:| dictionary. That means that extensive generation of lambdas and
|  +      exporting them outside of generator function may lead to a huge memory
|  +      overhead.

and point 5. here required my extended-funcref branch.

I do not really see any sense in allowing commands in lambdas, in
cases when commands are really needed lambdas should become
unreadable. Your example in my syntax is simply

    \v: (a:v < 0 ? a:v * 3.12 : a:v * -3.12)

>
>
> The implementation also takes items from the context, thus creating a
> closure.  I don't think that should be specific to a lambda, defining a
> function inside another function should be able to do the same thing.
> After all, a lambda is just a short way of defining a nameless function.
>
> In the implementation it seems the dictionary storing the function-local
> variables is kept for a very long time.  This relies on the garbage
> collector.  It's better to use reference counting to be able to free the
> dictionary as soon as it's unused.
>
> Also, the lambda always keeps the function-local variable dict, even
> when it's not actually used.  That makes lambdas a expensive.
> It would be better to explicitly state the lambda is using its context.
> Then we can also do that with ":function", so that we are not forced to
> use a lambda if we want a closure.

Note that my variant did not avoid these problems: I simply stored a
whole funccall structure in addition to storing pointers to in-lambdas
l:.

If there was VimL parser I would suggest to determine which variables
are “captured” from the outer scope, AFAIR Python does something like
this. But VimL has no parser… though evalX probably may be modified to
do this when skipping, with Ex commands this would be harder. There is
another possible solution: explicitly define which variables from the
outer scope are used: e.g.

    function Foo(arg1, arg2)
        let l = 42
        function Bar(arg1, <a:arg2, <l)
            return [a:arg1, a:arg2, l]
        endfunction
        echo Bar(45)
    endfunction
    call Foo(47, 43)
    " Echoes [45, 43, 42]

In this case ellipsis for varargs functions should be the last entity
before the first `<…` argument, for lambdas syntax is the same.

>
> However, I'm not sure we need this.  It is possible to bind a function
> to a dictionary, which can then contain anything that's to be kept
> between calls.
>
>
> Being able to pass a function to map(), sort(), etc. is good.  However,
> it looks like in the implementation only VAR_FUNC is supported, not
> VAR_PARTIAL.  It should be both.
>
>
> --
> What is the difference between a professional and an amateur?
> The ark was built by an amateur; professionals gave us the Titanic.
>
>  /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
> ///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
> \\\  an exciting new programming language -- http://www.Zimbu.org        ///
>  \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///
>
> --
> --
> 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.

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