6

I'm trying to understand the code suggested in https://vi.stackexchange.com/a/28506/6189:

function MyLinks(pat, strip) abort
  return glob(a:pat, v:false, v:true)
        \ ->map({_, v -> printf('[%s](%s)', fnamemodify(v, ':t:r')->substitute(printf('^%s', a:strip), '', ''), fnamemodify(v, ':t'))})
        \ ->join("\n")
endfunction

And I'm wondering what's v in this context? v:false, v:true, {_, v ->, and fnamemodify(v,?

What is v referring to? Is it a variable(if so, what's its value and how'd that get assigned?)?

1

2 Answers 2

5

It's the formal parameter name, chosen by the person who has written this code, to the lambda expected by map(). Almost anything would have been valid.

map() calls the lambda with 2 parameters for each element in the list: the index of the element (ignored here -> _), and the element (arbitrary named v). I guess the choice of using v stems from the traditional v:val available in map() historical string parameter.

See :h lambda (IIRC) and :h map().

5

And I'm wondering what's v in this context? v:false, v:true, {_, v ->, and fnamemodify(v,?

There are two separate instances of v here and they mean two different things.

Vim variables under the v: namespace

Vim has a list of special variables under the v: namespace. Note that v: is fixed here. Variables here include v:argv (the arguments passed to the vim command), v:version with a simple version number, and v:val which can be used in map() or filter() expressions to refer to the current item in the iteration.

Vim also includes constants here and v:true and v:false are examples here. These are constants that evaluate to the values in the boolean type. Older versions of Vim didn't have a boolean type and used 1 and 0 to indicate true or false (numeric values actually still work everywhere.) When a boolean type was introduced, the values were added to the v: namespace to prevent conflicts with any previous usage of those names.

See :help vim-variable for a comprehensive list of the v: variables.

Argument name in a lambda expression

The {_, v -> syntax starts a lambda expression, which is a way to define a function on the spot, using very short syntax. It's typically used together with map() and filter() since they take function arguments.

The part before the -> lists the arguments taken by the lambda. Since map() iterates over a Dict, you might want to use something like {key, value -> ...} since that's what the lambda function gets when it's called.

But since the key argument is not really used anywhere, you can just call it _, which is a useful placeholder for an argument you need to receive but will not be using.

If you were to use a lambda {key, value -> ...} (or even {_, value -> ...}), you would refer to the second argument as value, so you'd use fnamemodify(value, ':t:r') and so on. But since the point of a lambda is brevity, it makes sense to shorten it to just v, especially since you need to repeat that at least twice and in this case three times.

The lambda expression is just an unnamed function. If you wanted to, you could have written a function instead:

function! FormatLink(key, value)
    return printf('[%s](%s)',
        \ fnamemodify(a:value, ':t:r')->substitute('^string_', '', ''),
        \ fnamemodify(a:value, ':t'))
endfunction

Notice that in a function I'm referring to those by a:value, another advantage of lambda expressions is that you don't need to use the a: prefix for an argument.

I also had to modify the example slightly, since I didn't have access to a:strip from the other function. Which shows one advantage of lambda in that they create a closure inside the function where they're called (which means you can access that function's arguments and local variables.) You'd have to pass them as additional arguments to a named function, which is not always possible (such as in the case of using one in map().)

To use this function with a map(), you would need to use ->map(function('FormatLink')), which shows yet another advantage of lambdas in that you can use them directly as a Funcref, while for a named function you need to wrap it in function() and refer to its name by a string.

See :help map(), which has some more useful examples including lambdas and more pointers if you're interested.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.