In perl6 I define a subroutine with two parameters, one a scalar and the other an array. When I call the subroutine I receive a run-time error saying that only one parameter was passed when two were expected.
I have tried redefining the subroutine with only one parameter, once for each parameter type, and these cases succeed.
my #bb="red", "orange", "yellow", "green", "bleu", "indigo", "violet";
sub1(#bb,123);
sub sub1(#val2, $v) {
print "\#val2 = #val2\n";
print "\$v = $v\n";
}
I expect the output to be:
red orange yellow green blue indigo violet
123
The actual result is:
Too few positionals passed; expected 2 arguments but got 1
Related
I have a code like this, needs to be modified in such a way that -
the selection condition could be passed as an argument (one of the function arguments must be lambda with a value by default - the condition that was specified in your option).
This program calculates the sum of digits in multiples of 3
Example:
INPUT : 123456789
OUTPUT: 18 (3+6+9 = 18)
Code:
fun main() {
val s = readLine();
println(s?.map(Character::getNumericValue)?.filter{ it.toInt() % 3 == 0 }?.sum());
}
I find Lambda in Kotlin to be very confusing and on the top of it is "it".
There are two things I know about "it" and i.e.
If your Lambda has their own argument, you can replace its name with "it".
"It" is an automatically generated name for your Lambda, if it has
only one argument, and you don't specify a different argument name.
Still I don't understand what actually passes as "it".
For E.g. I wanted to apply modulo function on each element of a 3x3 matrix.
fun main(){
var result = Array(3) {
IntArray(3) { 3;2;4;6;7;9;12;11;23 }
}
result = Array(3){ IntArray(3) {it%2} }
println(result.joinToString("\n") { it.joinToString(" ") })
}
Here I assumed that "it" takes each element of the matrix which is clearly not the case as my output was:
0 1 0
0 1 0
0 1 0
So can you please explain me how "it" works, what is happening here? and what would be the correct way to implement this program?
Your line
result = Array(3){ IntArray(3) {it%2} }
isn't doing anything to the original Array that result is pointing at. You are creating a brand new group of array objects by calling the Array and IntArray constructors.
The lambda that you pass to the IntArray constructor has an input parameter that represents the array index, and the return value of your lambda is what will be put into the array at that index. So in this case it is the array index, and your lambda is returning 0 and 1 for even and odd indices respectively.
You are also instantiating your array incorrectly to begin with. Your lambda that you pass to that IntArray constructor is throwing away a bunch of pointless Int values and then returning 23 for each item. So you've created a 3x3 matrix that is completely filled with the number 23.
The correct syntax for creating an array with explicit values is to use arrayOf or intArrayOf.
val result = arrayOf(
intArrayOf(3, 2, 4),
intArrayOf(6, 7, 9),
intArrayOf(12, 11, 23)
)
To modify all the values of an array, you typically iterate the traditional way, not with a lambda:
for (innerArray in result) {
for (i in innerArray.indices)
innerArray[i] = innerArray[i] % 2
}
You were probably thinking of the map function, which lets you pass a lambda and returns a new List with the lambda function applied to every element of the input collection. Or when working with collections other than arrays, you can use forEach or onEach to iterate them without modifying them.
Suppose I have the following code:
my constant #suits = <Clubs Hearts Spades Diamonds>;
my constant #values = 2..14;
class Card {
has $.suit;
has $.value;
# order is mnemonic of "$value of $suit", i.e. "3 of Clubs"
multi method new($value, $suit) {
return self.bless(:$suit, :$value);
}
}
It defines some suits and some values and what it means to be a card.
Now, to build a deck, I essentially need to take the cross product of the suits and the values and apply that to the constructor.
The naiive approach to do this, would of course be to just iterate with a loop:
my #deck = gather for #values X #suits -> ($v, $c) {
take Card.new($v, $c);
}
But this is Raku, we have a cross function that can take a function as an optional argument!, so of course I'm gonna do that!
my #deck = cross(#values, #suits, :with(Card.new));
# Unexpected named argument 'with' passed
# in block <unit> at .\example.raku line 36
... wait no.
What about this?
my #deck = cross(#values, #suits):with(Card.new);
# Unexpected named argument 'with' passed
# in block <unit> at .\example.raku line 36
Still nothing. Reference maybe?
my #deck = cross(#values, #suits):with(&Card.new);
# ===SORRY!=== Error while compiling D:\Code\Raku/.\example.raku
# Illegally post-declared type:
# Card used at line 36
I read somewhere I can turn a function into an infix operator with []
my #deck = cross(#values, #suits):with([Card.new]);
# Unexpected named argument 'with' passed
# in block <unit> at .\example.raku line 36
That also doesn't work.
If classes are supposed to just be modules, shouldn't I then be able to pass a function reference?
Also why is it saying 'with' is that's unexpected? If I'm intuiting this right, what it's actually complaining about is the type of the input, rather than the named argument.
The error message is indeed confusing.
The :with parameter expects a Callable. Card.new is not a Callable. If you write it as :with( { Card.new($^number, $^suit) } ), it appears to work.
Note that I did not use $^value, $^suit, because they order differently alphabetically, so would produce the values in the wrong order. See The ^ twigil for more information on that syntax.
The error is LTA, this makes it a little bit better.
To get back to your question: you can find the code object that corresponds to Card.new with ^find_method. However, that will not work, as Card.new actually expects 3 arguments: the invocant (aka self), $value and $suit. Whereas the cross function will only pass the value and the suit.
The title of your question is “How do I take a reference to new?”, but that is not really what you want to do.
Raku being Raku, you can actually get a reference to new.
my $ref = Card.^lookup('new');
You can't use it like you want to though.
$ref(2,'Clubs'); # ERROR
The problem is that methods take a class or instance as the first argument.
$ref(Card, 2,'Clubs');
You could use .assuming to add it in.
$ref .= assuming(Card);
$ref(2,'Clubs');
But that isn't really any better than creating a block lambda
$ref = { Card.new( |#_ ) }
$ref(2,'Clubs');
All of these work:
cross( #values, #suits ) :with({Card.new(|#_)}) # adverb outside
cross( #values, #suits, :with({Card.new(|#_)}) ) # inside at end
cross( :with({Card.new(|#_)}), #values, #suits ) # inside at beginning
#values X[&( {Card.new(|#_)} )] #suits # cross meta-op with fake infix op
do {
sub new-card ($value,$suit) { Card.new(:$value,:$suit) }
#values X[&new-card] #suits
}
do {
sub with ($value,$suit) { Card.new(:$value,:$suit) }
cross(#values,#suits):&with
}
Let's say I've the following:
sealed class Color(val name: String) {
object Red : Color("red")
object Green : Color("green")
object Blue : Color("blue")
object Pink : Color("pink")
object Yellow : Color("yellow")
}
Is it possible to check if a color is a primary one using a when statement i.e.:
when(color) {
is Red, Green, Blue -> // primary color work
is Pink -> // pink color work
is Yellow -> // yellow color work
}
Yes. According to the grammar of when
when
: "when" ("(" expression ")")? "{"
whenEntry*
"}"
;
whenEntry
: whenCondition{","} "->" controlStructureBody SEMI
: "else" "->" controlStructureBody SEMI
;
whenCondition
: expression
: ("in" | "!in") expression
: ("is" | "!is") type
;
the {","} means the element can be repeated more times separated by commas. Note however that you have to repeat is too and smartcasts wont work if you do with different unrelated types.
In addition to the other answers, you can do it slightly more concisely by omitting the is entirely:
when (color) {
Red, Green, Blue -> // ...
Pink -> // ...
Yellow -> // ...
}
This is checking the values for equality, unlike the is code which is checking the types. (Red, Green, &c are objects as well as types, which is why both work. I suspect that this way may be fractionally more efficient, too.)
If the condition of if is False, instead of empty output, REPL gives () (an empty List?)
> put 1 if True
1
> put 1 if False
() # ← What is this?
What does () mean?
In earlier versions of this endlessly edited answer I wrote that "The REPL isn't doing anything special". But of course I was wrong. The REPL evaluates a line of code. If it generates output, it displays that output and that's it. If it doesn't, it says the value of the last statement. See JJ's answer.
The () you get means an empty list.
In earlier versions of this answer I agreed with you that it was an empty List. But of course I was wrong. In this instance it's a subtype of List. See Brad's answer.)
Arguably I'd best just delete this answer. :)
The following is what remains of possible value to this answer until someone else explains what else I've got wrong...
What Raku is doing
A statement evaluates to a value.
A statement can be just an expression.
An expression can be just a literal value:
> 42
42
A literal list of values evaluates to a List:
> 42, 99
(1 99)
An empty list is displayed as (). This can mean either an empty List:
> ()
() # <-- empty `List`
> List.new
() # <-- empty `List`
> 'aa' ~~ m:g/b/
() # <-- empty `List`
or an empty list that's a sub-type of List, but which reuses the same stringification, e.g. a Slip:
> Empty
() # <-- empty `Slip`
> Slip.new
() # <-- empty `Slip`
Statements can also evaluate to a single value:
> if True { 42 }
42
or a list:
> if True { 42, 99 }
(42 99)
Some statements evaluate to an empty list. Your question is one such example:
> if False {}
()
As Brad points out, that's an empty Slip, specifically the Empty instance.
Actually your question is incorrect.
What you really get back is an empty Slip.
Specifically, you get back a specific instance of it that is called Empty.
So it does in fact give you an Empty output.
TLDR; It returns Empty because it has to return something, and an empty Slip is more useful in list operations than any other "empty" value.
What Slip does is insert itself into the outer listy value.
say (1, 2, 3, (4, 5)).perl;
# (1, 2, 3, (4, 5))
say (1, 2, 3, (4, 5).Slip).perl;
# (1, 2, 3, 4, 5)
The reason for the existence of Slip is that Perl 6 doesn't flatten values by default.
sub return-list () { 4, 5 }
say (1, 2, 3, return-list()).perl;
# (1, 2, 3, (4, 5))
(Before the official release it used to flatten values in some cases, and it was both confusing and difficult to work-around)
So the feature of Slip was introduced for instances where you really did want it to flatten.
sub return-slip () { slip 4, 5 }
say (1, 2, 3, return-slip()).perl;
# (1, 2, 3, 4, 5)
Note that it only does one level of flattening.
sub return-structured-slip () {
slip 4, (5,)
}
say (1, 2, 3, return-structured-slip()).perl;
# (1, 2, 3, 4, (5,))
This is really useful to do a grep as a part of map code.
say (0..10).map: { $_, $_² if .is-prime }
# ((2 4) (3 9) (5 25) (7 49))
It can also be used for leaving off values when calling a routine.
my $a;
my $b = 1;
say(
( $a.perl if $a ),
( $b.perl if $b ),
)
One useful feature of singular Empty, is that you can match against it.
multi sub foo ($_){.say}
multi sub foo (Empty){ say 'Hello, World' }
foo Empty; # Hello, World
foo (1 if 0); # Hello, World
Note that it is possible to get an empty Slip that is not the singular value Empty. In which case it will not match.
|()
().Slip
It is returned value empty Slip (Empty). Try
say {put 1 if False}() ~~ Empty
You can use that … if False return Empty with List:
dd (2..100).map: { $_² if .is-prime }
Similarly, … with Nil and Nil andthen … return Empty.
All answers so far are excellent, explaining what's going on under the hood. But I'll try to answer your question directly.
If the condition of if is False, instead of empty output, REPL gives () (an empty List?)
The key to this is that you're working on the REPL. The REPL prints the output of a block if there's some; if there's no output, it prints whatever the expression returns. Let's then deal with your two options as blocks; what is inside the parentheses is what you would actually type in the REPL:
say (put 1 if True).^name # OUTPUT: «1Bool»
That's right. The REPL will see the output, 1, and print that. The block result, True in this case since that's what put returns, is dropped by the REPL. What happens in the second case?
say (put 1 if False).^name # OUTPUT: «Slip»
In this case, there's no output. The REPL would take (put 1 if False) as an expression, and prints () which, in this case, is a Slip. As indicated in #raiph answer, that's what if False {} returns, so that's what you get in your REPL.