why doesn't min take more than 1 parameter?

26 views
Skip to first unread message

L A Walsh

unread,
Jan 2, 2021, 9:49:12 AM1/2/21
to Vim Users
I have the expression:

trunc(1+log(1+line('$'))/log(10))

to give me the width of the number columns when numbering is
on. Seems that it is reserving a minimum of 3 columns, so I tried
using the 'min' function:

trunc(min(3,1+log(1+line('$'))/log(10)))

but I get E118: Too many arguments for function: min.

huh? so how does one use 'min' to determine the lowest of 2 or
more numbers, or why doesn't the above work? :-(


*sigh*,
tnx


Yongwei Wu

unread,
Jan 2, 2021, 9:57:30 AM1/2/21
to vim...@googlegroups.com
Just do ":help min()", it will tell you:

min({expr}) Return the minimum value of all items in {expr}.
{expr} can be a |List| or a |Dictionary|.

So the simplest solution seems to be:

trunc(min([3, float2nr(1+log(1+line('$'))/log(10))]))

--
--
You received this message from the "vim_use" 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_use" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vim_use+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/vim_use/5FF08799.3040702%40tlinx.org.


--
Yongwei Wu
URL: http://wyw.dcweb.cn/

Tim Chase

unread,
Jan 2, 2021, 9:57:39 AM1/2/21
to L A Walsh, vim...@googlegroups.com
On 2021-01-02 06:47, L A Walsh wrote:
> trunc(min(3,1+log(1+line('$'))/log(10)))
>
> but I get E118: Too many arguments for function: min.

min() expects a single list-like argument so try

trunc(min([3,1+log(1+line('$'))/log(10)]))

which creates a list-literal with "3" as the first item and your 1+…
as the second element.

-tim



Tony Mechelynck

unread,
Jan 2, 2021, 10:48:48 AM1/2/21
to vim_use, L A Walsh
Using a single list-like argument is more general: it allows
determining the minimum of any number of values. If it accepted only
two Float arguments, then to determine the minimum of 8 values you
would have to do for instance

:let result = min(min(min(arg1, arg2), min(arg3, arg4)), min(min(arg5,
arg6), min(arg7, arg8)))

while now you can do

:let result = min([arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8])

which is much more elegant.

Best regards,
Tony.

Tim Chase

unread,
Jan 2, 2021, 11:02:05 AM1/2/21
to Tony Mechelynck, vim...@googlegroups.com, L A Walsh
though a lot of vim stuff takes inspiration from
Python where min() is a vararg function letting
you do as the OP requests

min(arg1, arg2, arg3, arg4, …)

so it's a reasonable sort of hope/expectation.
It just doesn't happen to be a vim thing.

-tim




L A Walsh

unread,
Jan 3, 2021, 7:07:09 PM1/3/21
to wuyo...@gmail.com, vim...@googlegroups.com
On 2021/01/02 06:57, Yongwei Wu wrote:
> Just do ":help min()", it will tell you:
>
> min({expr}) Return the minimum value of all items in {expr}.
> {expr} can be a |List| or a |Dictionary|.
>
> So the simplest solution seems to be:
>
> trunc(min([3, float2nr(1+log(1+line('$'))/log(10))]))
>
---
Thanks, when I typed ":help min()", I got
min({list}), and didn't know if the curly braces, "{}"
were needed, but never would have guess I needed
square brackets "[]".

I had 'trunc' to convert from float to a truncated
integer, but notice that you are using "float2nr".

Didn't know I would have needed that either (I had
used the output of 'printf' to go from a number to
a string.

Thanks for the hints and, especially, the example.

L A Walsh

unread,
Jan 4, 2021, 5:16:20 PM1/4/21
to Tim Chase, Tony Mechelynck, vim...@googlegroups.com
On 2021/01/02 08:01, Tim Chase wrote:
> On 2021-01-02 16:48, Tony Mechelynck wrote:
>
>> Using a single list-like argument is more general: it allows
>> determining the minimum of any number of values. If it accepted only
>> two Float arguments, then to determine the minimum of 8 values you
>> would have to do for instance
>>
----
I asked why it didn't seem to take more than one parameter.
That ':help min' shows min({list}), which really means
min([itema, itemb...]), is what was throwing me.
>> :let result = min(min(min(arg1, arg2), min(arg3, arg4)),
>> min(min(arg5, arg6), min(arg7, arg8)))
>>
>> while now you can do
>>
>> :let result = min([arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8])
>>
>> which is much more elegant.
>>
True. Even more elegant, might have been:
result = min(1,2,3,4,5,6,7,8);
( = 1)


On 2021/01/02 08:01, Tim Chase wrote:
> though a lot of vim stuff takes inspiration from
> Python ...
>
I think vim was around before python. vim would have drawn from
'vi' and, earlier, 'ed', sorta like early perl was an attempt to
mix early shell tools (sed, tr, sort, etc), with a shell like
language. Passing args in a list seems more like lisp -- maybe
drawing examples from emacs?


Hey, do you know how to determine the number of columns taken up by
fdc? Doesn't seem I can use fdc directly as a number though.

Thanks!






Charles Campbell

unread,
Jan 4, 2021, 5:48:48 PM1/4/21
to vim...@googlegroups.com, L A Walsh
L A Walsh wrote:
>
> Hey, do you know how to determine the number of columns taken up by
> fdc?  Doesn't seem I can use fdc directly as a number though.

Try using &fdc ; the ampersand means to grab the information from an option.

Regards,
Chip Campbell

Tim Chase

unread,
Jan 4, 2021, 8:03:21 PM1/4/21
to vim...@googlegroups.com
On 2021-01-04 14:14, L A Walsh wrote:
> On 2021/01/02 08:01, Tim Chase wrote:
> > though a lot of vim stuff takes inspiration from
> > Python ...
> >
> I think vim was around before python.

Both were originally released in 1991. However, some of the
vim-script language features like list-initializers and
dictionary-initializers and negative list-indexing came into vim long
after Python had them and they draw pretty strong syntactic influence
thence.

> vim would have drawn from 'vi' and, earlier, 'ed',

Indeed, vim does find its roots in vi(1) which in turn is the visual
mode of ex(1) which shares concepts with ed(1). (and if you are on
Twitter or Mastodon and enjoy ed(1), feel free to check out my
@ed1conf and @ed1...@bsd.network alter-ego accounts)

> Hey, do you know how to determine the number of columns taken up by
> fdc? Doesn't seem I can use fdc directly as a number though.

As Dr. Chip mentions, prefix the setting-name with an "&"

:echo 'The value of foldcolumn is set to '.&fdc

should do the trick.

-tim


L A Walsh

unread,
Jan 6, 2021, 2:37:31 PM1/6/21
to Tim Chase, Tony Mechelynck, vim...@googlegroups.com
On 2021/01/02 08:01, Tim Chase wrote
> though a lot of vim stuff takes inspiration from
> Python where min() is a vararg function letting
> you do as the OP requests
>
> min(arg1, arg2, arg3, arg4, …)
>
> so it's a reasonable sort of hope/expectation.
> It just doesn't happen to be a vim thing.
>
---
Is there any reason why vim couldn't have a simplified
version, "Min" that takes a variable number of args
rather than its current behavior of taking a fixed
number (1) of "list-args"?

I.e. it sounds like, by being declared "varargs",
that min could take a variable number of args (?).

Is a vim function capable of determining the type
of the arg(s) passed to it? Like if I passed
min(3,4,[1,2]), can vim determine that it got 3 arguments,
where it knows that they are two "plain" args, and
1 is a "List" such that it could automatically expand "List" args,
and "inline" its elements into 1 longer set of arguments
that 'min' can return the value of?

I.e., it seems like "min", rather than returning an "Error"
when presented with multiple-args, could simply return the
minimum of those args, _and_, if any of those args were a "List",
like [1,2], then merge those args into the set of multiple
args that was passed. This would mean that ([1,2]) would
automatically expand its List into multiple arguments (1,2), and
then return the "min" value, i.e. "doing the right thing", while
keeping compatibility with current behavior (except for returning
an error when unnecessary).

Wouldn't that be possible for "min" and similar functions
that can tell what the user wants, and just do it? (rather than
returning an error that doesn't seem necessary or useful)
> -tim
>
---
Thanks for the explanations! As you point out, vim, it
seems, could do the right thing while remaining functionally
compatible with older vim script.

-Linda

Salman Halim

unread,
Jan 6, 2021, 3:29:20 PM1/6/21
to Vim Users
While I can't explain why things work the way they do, here is a custom function that should do what you want (called Min); it takes a variable number of arguments, flattens incoming lists into a single list and then calls the built-in min. You can see that it uses the type() function to figure out the type of the incoming argument (to answer another question you asked herein):

function! Min( ... )
  let collection = []

  for entry in a:000
    if ( type( entry ) == v:t_list )
      call extend( collection, flatten( entry ) )
    else
      let collection += [ entry ]
    endif
  endfor

  return min( collection )
endfunction

" Sample call
" echo Min(9, 22, [5, [3, 7]])

--
--
You received this message from the "vim_use" 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_use" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vim_use+u...@googlegroups.com.


--
 
Salman

I, too, shall something make and glory in the making.

BPJ

unread,
Jan 6, 2021, 3:38:31 PM1/6/21
to vim_use
Den ons 6 jan. 2021 21:29Salman Halim <salma...@gmail.com> skrev:
While I can't explain why things work the way they do, here is a custom function that should do what you want (called Min); it takes a variable number of arguments, flattens incoming lists into a single list and then calls the built-in min. You can see that it uses the type() function to figure out the type of the incoming argument (to answer another question you asked herein):

function! Min( ... )
  let collection = []

  for entry in a:000
    if ( type( entry ) == v:t_list )
      call extend( collection, flatten( entry ) )
    else
      let collection += [ entry ]
    endif
  endfor

  return min( collection )
endfunction

" Sample call
" echo Min(9, 22, [5, [3, 7]])

Isn't the problem that the number of varargs to a Vimscript function is limited, while a List can have many more elements (although there is probably a limit there too)?


Salman Halim

unread,
Jan 6, 2021, 4:16:41 PM1/6/21
to Vim Users
Yes, 20. I agree with the problem. It's undoubtedly a holdover from when you had to use a:0, a:1, etc., and couldn't get a:000 (as a list), before proper lists were added.

I think the system could be extended to allow an arbitrary number of arguments for a:000 and still limit to up to 20 via the old mechanism: if you want to access the 21st on, use a:000 instead. 

Of course, if you have dozens and dozens of arguments, you could wrap them in a [] pair to convert it into a list of arbitrary length (that process isn't limited by the 20 function parameter limit). Programmatically speaking, if you're doing this dynamically, it seems to me as if creating a list of arbitrary length is better than creating an execute statement that takes a large number of individual parameters.

--

Salman

L A Walsh

unread,
Jan 6, 2021, 10:17:21 PM1/6/21
to Vim Users
On 2021/01/06 12:28, Salman Halim wrote:
> While I can't explain why things work the way they do, here is a
> custom function
---
That's just the thing -- the functions in Vim should be the most general
possible so custom solutions are rarely, if ever needed.

On 2021/01/06 13:16, Salman Halim wrote:
>
> Of course, if you have dozens and dozens of arguments, you could wrap
> them in a [] pair to convert it into a list of arbitrary length (that
> process isn't limited by the 20 function parameter limit).
> Programmatically speaking, if you're doing this dynamically, it seems
> to me as if creating a list of arbitrary length is better than
> creating an execute statement that takes a large number of individual
> parameters.
---
But non-programmatically, when you just want the min/max of 2, wouldn't
handling both cases be best? So other functions could pass large numbers of
parameters in a list, but simple cases wouldn't need the overhead or special
syntax.

If the function handled both cases min(3,4,5,[1,2]) would become
min(3,4,5,1,2) or min([3,4,5,1,2]) and either format would work. Then users
expecting simple like 'min(1,2)', would just have it work, while those
wanting more complex, could use the equivalent min([1,2]); Either way, it
would just "do the right thing" and not require the user to conform to one
one syntax or the other.

As you point out -- it can be done today -- it just hasn't been,
yet. :-)



Salman Halim

unread,
Jan 7, 2021, 12:36:59 AM1/7/21
to Vim Users
Obviously, your example was just to make a point because you can easily tell which of two numbers is the smaller, unless it's in a programming environment. 

That said, I don't know how I feel about it. I see your point as there are already plenty of API that now take an extra parameter to optionally return a list and some take variable arguments, such as printf, so individual functions do support multiple flavours. 

On the other hand, there is often stuff that doesn't do exactly what one thinks is intuitive (not just Vim), and I write variations to make it do what I want all the time. While it may be worth arguing that anything that takes a list should also accept multiple arguments and figure it out, the version I wrote took very little time. (I wrote it specifically for this email chain: I use the built-in min function quite happily.)

I guess I don't find typing 'min([5, 2, 12])' instead of 'min(5, 2, 12)' that cumbersome. Also, in most language situations that arise, you usually pass min an array. (I realize that JavaScript and python do allow both, as you've also mentioned.)

Best regards,

--

Salman

--
--
You received this message from the "vim_use" 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_use" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vim_use+u...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages