Nikolay Pavlov wrote:

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

Yes, that is an option.  It does restrict the situations when it can be
used, but since a multi-statement lambda quickly becomes unreadable,
there may not be much use for it anyway.

It does require the possibility to create a closure with a nested
function, in case we do need multiple statements, but if we do support
closures it should be done for both lambda and normally defined
functions anyway.

I do not like the cryptic syntax.  I think the word "lambda" is good,
unless we can think of something that is easy to recognize.
One possible option is to focus on using the "gives" token:

        { a1, a2 -> a1 + a2 }

Even without an argument it can still be recognized:

        { -> string(Today()) }


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

Yes, for some places a ternary expression works.  However, Vim doesn't
have an expression with side effects.  Well, except when calling a
function, but that defeats the idea of the lambda.

Theoretically we could use ";" to separate expressions (like the comma
operator in C), but I wonder we should actually do this:

        { a -> tmp = a * 5; [tmp, tmp + 2, tmp + 5] }

In this context it is useful, but in other places it's an invitation to
write confusing code.

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

Specifying which variables from the environment are used makes it a lot
more efficient, but it can also be a hassle.  A simpler, brute-force way
is to specify that the function (or lambda) is a closure.  It would only
use variables from the context that it's in, not a level up.  So keeping
a reference to the dict with the local variables.

Since it's also possible to bind a function to a dict, and use that dict
to store any state, I think that this is actually not all that important
to add.  Perhaps we should first have a good example where a closure is
required or much nicer than a partial bound to a dict.

So, of the three things that the CL was split up into:
1. pass function to filter() and map()
2. implement lambda
3. implement closure

The first is done.  Implementing lambda seems useful enough.  I'm not so
sure about the need for supporting closure.

-- 
$ echo pizza > /dev/oven

 /// Bram Moolenaar -- b...@moolenaar.net -- 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 vim_dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui