I'm trying to write a Raku script to be called e.g.
script 1.2 1.117 -2 0.037
I.e., the idea is to create a sub MAIN(@numbers)
and somehow get the array @numbers
as Real (not Str, not IntStr). A way to do so is to cast each element (if possible) in a for
, but I'm sure there is a more elegant solution.
Variable number of arguments means the function can accept any number of arguments. In JavaScript, there are two ways of writing a function that accepts any number of arguments: Using the arguments object. Using the rest parameter. How to use the arguments object to create a function that accepts any number of arguments?
There is no function parameter limit, so you can call a function and pass in any number of arguments, regardless of what the function declaration specifies. There are two ways that can make it possible to create a function with any number of arguments specified. Watch a video course JavaScript - The Complete Guide (Beginner + Advanced)
The arguments is an Array-like object accessible inside functions containing the values of the arguments passed to that function. The rest parameter syntax allows adding an indefinite number of arguments as an array.
The difference between parameters and arguments is - function parameters are the names listed in the function's definition, and function arguments are the real values passed to the function when invoking it. Here is an example of using rest arguments. Copied!
I'll let readers judge whether the following is a technically atrocious hack, or looks hideously repugnant, or both. But it's the closest thing I'm aware of in current Raku syntax.
First, you need to accept a variable number of arguments. (You need that for even your code to work at all. I presume you typo'd.)
Rather than use *
or similar I'll use |
. We'll see why in a mo.
sub MAIN( |numbers ) { ... }
Next, I add a sub-signature.
sub MAIN( |numbers ( *@, :@reals = numbers».Real )) { ... }
This takes advantage of:
Named parameters being optional; and
Establishing a default value based on arguments bound to parameters to the left in a signature; and
Hiding this chicanery so the usage message is not affected, and so that (I think) the user cannot inject a value using --reals=...
or similar. (Actually, saying I think they can't is far too strong. I hope they can't.)
This is either a pretty terrible hack or just plain evil. Don't do this at home work!
The code so far presumes that the arguments are indeed Real
s. If they're not, things go wrong. We need to deal with that too.
So we add a subset
and add that to the signature:
subset Reals where *».Real».defined.all;
sub MAIN( Reals |numbers ( *@, :@reals = numbers».Real )) { ... }
Here we see the main reason I used |
rather than *
; it's the only way to write a type on the left of a slurpy, Without that I'd have to inline the where
and the whole thing would be even more unspeakably ugly than it is.
Thus we end up with:
subset Reals where *».Real».defined.all;
sub MAIN( Reals |numbers ( *@, :@reals = numbers».Real )) { .WHAT.say for @reals }
displaying, for your original command line:
(Rat)
(Rat)
(Int)
(Rat)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With