In the Perl 6 Signature docs, there's an example of an anonymous slurpy parameter:
sub one-arg (#) { }
sub slurpy (*#) { }
one-arg (5, 6, 7); # ok, same as one-arg((5, 6, 7))
slurpy (5, 6, 7); # ok
slurpy 5, 6, 7 ; # ok
There are no statements in the subroutine, mostly because the text around this is about the parameter list satisfying the signature rather than what the subroutine does with it.
I was playing with that and trying to make a subroutine that takes a list of one of more items (so, not zero items). I didn't particularly care to name them. I figured I'd still have access to the argument list in #_ even with the signature. However, you get #_ when you don't have a signature:
$ perl6
To exit type 'exit' or '^D'
> sub slurpy(*#) { say #_ }
===SORRY!=== Error while compiling:
Placeholder variable '#_' cannot override existing signature
------> sub⏏ slurpy(*#) { say #_ }
Is there another way to get the argument list, or does the anonymous parameter discard them? I see them used in the section on type constraints, but there isn't an example that uses any of the parameter values. Can I still get the argument list?
The values aren't discarded; you can for example access it through nextsame:
multi access-anon(*#) is default {
say "in first candidate";
nextsame;
}
multi access-anon(*#a) {
#a;
}
say access-anon('foo')
Output:
in first candidate
[foo]
But to get to your original objective (an array with at least one element), you don't actually need to access the list; you can use a sub-signature:
sub at-least-one(# [$, *#]) { }
at-least-one([1]); # no error
at-least-one([]); # Too few positionals passed; expected at least 1 argument but got only 0 in sub-signature
Does an anonymous parameter in a Perl 6 signature discard the value?
Yes, unless you capture an argument using some named parameter in the function's signature, it won't be available in the function's body. (PS: They're not literally discarded though, as moritz's answer shows.)
I figured I'd still have access to the argument list in #_ even with the signature.
#_ is not an alternative to using parameters - it is a parameter.
Every function has a well-defined signature that specifies its parameters, and they represent the only mechanism for the function body to get at the values the function is passed.
It's just that there are three different ways to declare a function signature:
If you explicitly write out a signature, that's what is used.
If you use placeholder parameters (#_ or $^foo etc.) in the body of the function, the compiler uses that information to build the signature for you: say { $^a + #_ }.signature; # ($a, *#_)
If neither of the above is the case, then the signature becomes:
In case of subroutines, one that accepts zero arguments: say (sub { 42 }).signature; # ()
In case of bare blocks, one that accepts zero or one argument available as $_: say { 42 }.signature; # (;; $_? is raw)
In all cases, the function ends up with an unambiguous signature at compile time. (Trying to use $^foo in a function that already has an explicit signature, is a compile-time error.)
Is there another way to get the argument list
Make sure to capture it with a non-anonymouys parameter. If you want it to be accessible as #_, then call it that in the explicit signature you're writing.
I was [...] trying to make a subroutine that takes a list of one of more items
You can use a sub-signature for that:
sub foo (*#_ [$, *#]) { ... };
Or alternatively a where constraint:
sub foo (*#_ where .so) { ... };
To have #_ populated, the signature either has to be implicit or explicit, not both.
sub implicit { say #_ } # most like Perl 5's behaviour
sub explicit ( *#_ ) { say #_ }
sub placeholder { $^a; say #_ }
This applies to blocks as well
my &implicit = { say #_ }
my &explicit = -> *#_ { say #_ }
my &placeholder = { $^a, say #_ }
Blocks can also have an implicit parameter of $_, but #_ takes precedence if it is there.
{ say $_ }(5) # 5
$_ = 4;
{ #_; say $_ }(5) # 4
It makes sense to do it this way because one programmer may think it works the way you think it does, or that it is slurpy like it would be if implicit, and another may think it gets all of the remaining arguments.
sub identical ( #_ ) { say #_ }
sub slurpy ( *#_ ( #, *# ) ) { say #_ } # same as implicit
sub slurpy2 ( **#_ ( #, *# ) ) { say #_ } # non-flattening
sub remaining ( #, *#_ ) { say #_ }
identical [1,2]; # [1 2]
slurpy $[1,2],3,4,5; # [[1 2] 3 4 5]
slurpy2 [1,2],3,4,5; # [[1 2] 3 4 5]
remaining [1,2],3,4,5; # [3 4 5]
#_ may also be added as a mistake, and in that case it would be preferable for it to produce an error.
There is no way to get at the raw arguments without declaring a capture parameter.
sub raw-one ( |capture ( # ) ) { capture.perl }
sub raw-slurpy ( |capture, *# ) { capture.perl }
raw-one [1,2]; # \([1, 2])
raw-slurpy 1,2 ; # \(1, 2)
Related
I really appreciate the Raku's &?BLOCK variable – it lets you recurse within an unnamed block, which can be extremely powerful. For example, here's a simple, inline, and anonymous factorial function:
{ when $_ ≤ 1 { 1 };
$_ × &?BLOCK($_ - 1) }(5) # OUTPUT: «120»
However, I have some questions about it when used in more complex situations. Consider this code:
{ say "Part 1:";
my $a = 1;
print ' var one: '; dd $a;
print ' block one: '; dd &?BLOCK ;
{
my $a = 2;
print ' var two: '; dd $a;
print ' outer var: '; dd $OUTER::a;
print ' block two: '; dd &?BLOCK;
print "outer block: "; dd &?OUTER::BLOCK
}
say "\nPart 2:";
print ' block one: '; dd &?BLOCK;
print 'postfix for: '; dd &?BLOCK for (1);
print ' prefix for: '; for (1) { dd &?BLOCK }
};
which yields this output (I've shortened the block IDs):
Part 1:
var one: Int $a = 1
block one: -> ;; $_? is raw = OUTER::<$_> { #`(Block|…6696) ... }
var two: Int $a = 2
outer var: Int $a = 1
block two: -> ;; $_? is raw = OUTER::<$_> { #`(Block|…8496) ... }
outer block: -> ;; $_? is raw = OUTER::<$_> { #`(Block|…8496) ... }
Part 2:
block one: -> ;; $_? is raw = OUTER::<$_> { #`(Block|…6696) ... }
postfix for: -> ;; $_ is raw { #`(Block|…9000) ... }
prefix for: -> ;; $_ is raw { #`(Block|…9360) ... }
Here's what I don't understand about that: why does the &?OUTER::BLOCK refer (based on its ID) to block two rather than block one? Using OUTER with $a correctly causes it to refer to the outer scope, but the same thing doesn't work with &?BLOCK. Is it just not possible to use OUTER with &?BLOCK? If not, is there a way to access the outer block from the inner block? (I know that I can assign &?BLOCK to a named variable in the outer block and then access that variable in the inner block. I view that as a workaround but not a full solution because it sacrifices the ability to refer to unnamed blocks, which is where much of &?BLOCK's power comes from.)
Second, I am very confused by Part 2. I understand why the &?BLOCK that follows the prefix for refers to an inner block. But why does the &?BLOCK that precedes the postfix for also refer to its own block? Is a block implicitly created around the body of the for statement? My understanding is that the postfix forms were useful in large part because they do not require blocks. Is that incorrect?
Finally, why do some of the blocks have OUTER::<$_> in the but others do not? I'm especially confused by Block 2, which is not the outermost block.
Thanks in advance for any help you can offer! (And if any of the code behavior shown above indicates a Rakudo bug, I am happy to write it up as an issue.)
That's some pretty confusing stuff you've encountered. That said, it does all make some kind of sense...
Why does the &?OUTER::BLOCK refer (based on its ID) to block two rather than block one?
Per the doc, &?BLOCK is a "special compile variable", as is the case for all variables that have a ? as their twigil.
As such it's not a symbol that can be looked up at run-time, which is what syntax like $FOO::bar is supposed to be about afaik.
So I think the compiler ought by rights reject use of a "compile variable" with the package lookup syntax. (Though I'm not sure. Does it make sense to do "run-time" lookups in the COMPILING package?)
There may already be a bug filed (in either of the GH repos rakudo/rakudo/issues or raku/old-issues-tracker/issues) about it being erroneous to try to do a run-time lookup of a special compile variable (the ones with a ? twigil). If not, it makes sense to me to file one.
Using OUTER with $a correctly causes it to refer to the outer scope
The symbol associated with the $a variable in the outer block is stored in the stash associated with the outer block. This is what's referenced by OUTER.
Is it just not possible to use OUTER with &?BLOCK?
I reckon not for the reasons given above. Let's see if anyone corrects me.
If not, is there a way to access the outer block from the inner block?
You could pass it as an argument. In other words, close the inner block with }(&?BLOCK); instead of just }. Then you'd have it available as $_ in the inner block.
Why does the &?BLOCK that precedes the postfix for also refer to its own block?
It is surprising until you know why, but...
Is a block implicitly created around the body of the for statement?
Seems so, so the body can take an argument passed by each iteration of the for.
My understanding is that the postfix forms were useful in large part because they do not require blocks.
I've always thought of their benefit as being that they A) avoid a separate lexical scope and B) avoid having to type in the braces.
Is that incorrect?
It seems so. for has to be able to supply a distinct $_ to its statement(s) (you can put a series of statements in parens), so if you don't explicitly write braces, it still has to create a distinct lexical frame, and presumably it was considered better that the &?BLOCK variable tracked that distinct frame with its own $_, and "pretended" that was a "block", and displayed its gist with a {...}, despite there being no explicit {...}.
Why do some of the blocks have OUTER::<$_> in them but others do not?
While for (and given etc) always passes an "it" aka $_ argument to its blocks/statements, other blocks do not have an argument automatically passed to them, but they will accept one if it's manually passed by the writer of code manually passing one.
To support this wonderful idiom in which one can either pass or not pass an argument, blocks other than ones that are automatically fed an $_ are given this default of binding $_ to the outer block's $_.
I'm especially confused by Block 2, which is not the outermost block.
I'm confused by you being especially confused by that. :) If the foregoing hasn't sufficiently cleared this last aspect up for you, please comment on what it is about this last bit that's especially confusing.
During compilation the compiler has to keep track of various things. One of which is the current block that it is compiling.
The block object gets stored in the compiled code wherever it sees the special variable $?BLOCK.
Basically the compile-time variables aren't really variables, but more of a macro.
So whenever it sees $?BLOCK the compiler replaces it with whatever the current block the compiler is currently compiling.
It just happens that $?OUTER::BLOCK is somehow close enough to $?BLOCK that it replaces that too.
I can show you that there really isn't a variable by that name by trying to look it up by name.
{ say ::('&?BLOCK') } # ERROR: No such symbol '&?BLOCK'
Also every pair of {} (that isn't a hash ref or hash index) denotes a new block.
So each of these lines will say something different:
{
say $?BLOCK.WHICH;
say "{ $?BLOCK.WHICH }";
if True { say $?BLOCK.WHICH }
}
That means if you declare a variable inside one of those constructs it is contained to that construct.
"{ my $a = "abc"; say $a }"; # abc
say $a; # COMPILE ERROR: Variable '$a' is not declared
if True { my $b = "def"; say $b } # def
say $b; # COMPILE ERROR: Variable '$b' is not declared
In the case of postfix for, the left side needs to be a lambda/closure so that for can set $_ to the current value.
It was probably just easier to fake it up to be a Block than to create a new Code type just for that use.
Especially since an entire Raku source file is also considered a Block.
A bare Block can have an optional argument.
my &foo;
given 5 {
&foo = { say $_ }
}
foo( ); # 5
foo(42); # 42
If you give it an argument it sets $_ to that value.
If you don't, $_ will point to whatever $_ was outside of that declaration. (Closure)
For many of the uses of that construct, doing that can be very handy.
sub call-it-a (&c){
c()
}
sub call-it-b (&c, $arg){
c( $arg * 10 )
}
for ^5 {
call-it-a( { say $_ } ); # 0 1 2 3 4
call-it-b( { say $_ }, $_ ); # 010203040
}
For call-it-a we needed it to be a closure over $_ to work.
For call-it-b we needed it to be an argument instead.
By having :( ;; $_? is raw = OUTER::<$_> ) as the signature it caters to both use-cases.
This makes it easy to create simple lambdas that just do what you want them to do.
This comes from this perl6/doc issue which also refers to these questions in the IRC channel
The documentation specifies how to constrain the arguments of a callable using a Signature literal:
sub f(&c:(Int, Str)) { say c(10, 'ten') };
(this would restrict the function argument to only those that take an Integer and a String as an argument).
However, in some other situations, where constraining can be used, for instance if you need to restrict the arity or the return values. However, is there any simpler way or syntax of doing this?
To enforce an arity of, for example, 2, then a signature literal can also be used:
sub foo(&x:($,$)) {
x(1,2)
}
Then this works:
foo -> $a, $b { say $a + $b }
While this dies:
foo -> $a { say $a }
This signature literal just means "any two arguments". The return type can also be constrained by similar means:
sub foo(&x:(--> Int)) {
say x()
}
Meaning this works:
foo sub (--> Int) { 42 }
But this dies:
foo sub () { "oops" }
Consider this program where I construct an Array in the argument list. Although there's a signature that accepts an Array, this calls the one that accepts a List:
foo( [ 1, 2, 3 ] );
multi foo ( Array #array ) { put "Called Array # version" }
multi foo ( Array $array ) { put "Called Array \$ version" }
multi foo ( List $list ) { put "Called List version" }
multi foo ( Range $range ) { put "Called Range version" }
I get the output from an unexpected routine:
Called Array $ version
If I uncomment that other signature, that one is called:
Called List version
Why doesn't it call the ( Array #array ) version? How is the dispatcher making its decision (and where is it documented)?
Why doesn't it call the ( Array #array ) version?
Your test foo call has just an Array ([1,2,3]) as its argument, not an Array of Arrays (eg [[1,2,3],[4,5,6]]).
(The # in #array indicates a value that does Positional, eg an array or a list. Array #array indicates the same thing but with the additional constraint that each element of the array, list or whatever is an Array.)
How is the dispatcher making its decision?
Simplifying, it's picking the narrowest matching type:
multi foo ( Array ) {} # Narrowest
multi foo ( List ) {} # Broader
multi foo ( Positional ) {} # Broader still
multi foo ( #array ) {} # Same as `Positional`
(Diagram of subtype relationships of Array, List and Positional.)
For lots of details see jnthn's authoritative answer to a related SO question.
(and where is it documented)?
I'm not sure about the doc. Multi-dispatch looks pretty minimal.
I made a really dumb mistake, and that's why I wasn't seeing what I expected. You can't constrain a variable that starts with #. Any constraint applies to its elements. The Array #array denotes that I have a positional sort of thing in which each element is an Array. This is the same thing that raiph said. The odd thing is that the grammar looks the same but it does different things. It's something I've tripped over before.
Since it's doing something different, it's not going to work out even if the data structure matches:
foo( [ [1], [2], [3] ] );
foo( [ 1, 2, 3 ] );
multi foo ( Array #array ) { put "Called Array # version" }
multi foo ( Array $array ) { put "Called Array \$ version" }
multi foo ( List $list ) { put "Called List version" }
multi foo ( Range $range ) { put "Called Range version" }
I still get the version I wouldn't expect based on the constraint and the data structure:
Called Array $ version
Called Array $ version
I think this is just going to be one of Perl 6's warts that normal users will have to learn.
There seems to be a trade off between the design documents (more complete but more outdated) and the documentation (known to be incomplete, as docs.perl6.org acknowledges, but hopefully more up-to-date). The former explains multisub resolution in Synopsis 12. Excerpt:
When you call a routine with a particular short name, if there are multiple visible long names, they are all considered candidates. They are sorted into an order according to how close the run-time types of the arguments match up with the declared types of the parameters of each candidate. The best candidate is called, unless there's a tie, in which case the tied candidates are redispatched using any additional tiebreaker strategies (see below). [...]
There are three tiebreaking modes, in increasing order of desperation:
A) inner or derived scope
B) run-time constraint processing
C) use of a candidate marked with "is default"
Tiebreaker A simply prefers candidates in an inner or more derived scope over candidates in an outer or less derived scope. For candidates in the same scope, we proceed to tiebreaker B.
In the absence of any constraints, ties in tiebreaker A immediately failover to tiebreaker C; if not resolved by C, they warn at compile time about an ambiguous dispatch. [...]
I don’t know enough about Perl 6 to testify as to its accuracy, but it seems to be in agreement with raith’s answer, and covers additional ground as well.
I'm trying to write a mini DSL for some specific task. For this purpose I've been trying to solve a problem like this below (without using parantheses):
give me 5 like romanLetter
give me 5 like word
where the first line would return "V" and the second "five"
My definitions for the first part give me 5 look like this
def give = { clos -> clos() }
def me = { clos -> [:].withDefault { it
println it}
}
and then give me 5 prints 5
The problem is how to add more metaclass methods on the right. E.g.
give me 5 like romanLetter -> prints V OR
give me 5 like word -> prints five
my intuition is that I define like as
Object.metaClass.like = {orth -> if (orth.equals("roman")){ println "V"}
else {println "five"} }
this metaClass method like works only if there is a returned value from the left to be applied to, right? I tried adding a return statement in all of the closures which are on the left side but I always receive
groovy.lang.MissingPropertyException: No such property: like
for class: com.ontotext.paces.rules.FERulesScriptTest ...
do you have an idea how shall I do?
========================================
Here is the application of what I'm asking for.
I want to make a rule as follows
add FEATURE of X opts A,B,C named Y
where add is a closure, of, opts and named are MetaClass methods (at least that's how i imagine it), X, A, B, C, Y are parameters most probably strings and FEATURE is either a MetaClass property, or a closure without arguments or a closure with arguments.
If FEATURE does not take arguments then it is enough that add takes FEATURE as argument and returns a value on which
Object.metaClass.of will be executed with parameter X
Object.metaClass.opts will be executed on the returned by OF value with parameters A, B, C
Object.metaClass.named will be executed on the returned by opts value with parameter Y
each one of these metaclass methods sets its parameter as a value in a map, which is passed to a JAVA method when named is called.
I'm not sure this is the best solution for such a problem, but it seems to me such for the moment. The problem is if FEATURE is not a property itself but a closure which takes argument (e.g. feature1 ARG1). Then
add feature1 ARG1 of X opts A,B,C named Y
and this is the case which I'm stuck with. add feature1 ARG1 is the give me 5 part and I'm trying to add the rest to it.
========================================================
EXAMPLES:
I need to have both of the following working:
add contextFeature "text" of 1,2,3 opts "upperCase" named "TO_UPPER"
add length named "LENGTH"
where in the first case by parsing the rule, whenever each metaclass method of, opts, named is called I fill in the corresponding value in the following map:
params = [feature: "text",
of: 1,2,3,
opts: "upperCase",
named: "TO_UPPER"]
ones this map is filled in, which happens when named is parsed, I call a java method
setFeature(params.of, params.named, params.opts, params.feature)
In the second case length is predefined as length = "length", params values will be only
params = [feature : length,
of: null,
opts: null,
named: "LENGTH"]
and since of is null another java method will be called which is addSurfaceFeature(params.feature, params.named). The second case is more or less streight forward, but the first one is the one I can't manage.
Thanks in advance! Iv
You can do this sort of thing... Does that get you close?
def contextFeature( type ) {
"FEATURE_$type"
}
// Testing
new IvitaParser().parse {
a = add text of 1,2,3 opts "upperCase" named "TO_UPPER"
b = add length named "LENGTH"
c = add contextFeature( "text" ) of 1,2,3 opts "upperCase" named "TO_UPPER"
}
assert a == [feature:'text', of:[1, 2, 3], opts:'upperCase', named:'TO_UPPER']
assert b == [feature:'length', of:null, opts:null, named:'LENGTH']
assert c == [feature:'FEATURE_text', of:[1, 2, 3], opts:'upperCase', named:'TO_UPPER']
// Implementation
class IvitaParser {
Map result
def parse( Closure c ) {
c.delegate = this
c.resolveMethod = Closure.DELEGATE_FIRST
c()
}
def propertyMissing( String name ) {
name
}
def add( String param ) {
result = [ feature:param, of:null, opts:null, named:null ]
this
}
def of( Object... values ) {
result.of = values
this
}
def named( String name ) {
result.named = name
result
}
def opts( String opt ) {
result.opts = opt
this
}
}
You can even get rid of the quotes on the definition:
a = add text of 1,2,3 opts upperCase named TO_UPPER
b = add length named LENGTH
As the propertyMissing method just converts unknown properties into a String of their name
I was wondering. Are there languages that use only pass-by-reference as their eval strategy?
I don't know what an "eval strategy" is, but Perl subroutine calls are pass-by-reference only.
sub change {
$_[0] = 10;
}
$x = 5;
change($x);
print $x; # prints "10"
change(0); # raises "Modification of a read-only value attempted" error
VB (pre .net), VBA & VBS default to ByRef although it can be overriden when calling/defining the sub or function.
FORTRAN does; well, preceding such concepts as pass-by-reference, one should probably say that it uses pass-by-address; a FORTRAN function like:
INTEGER FUNCTION MULTIPLY_TWO_INTS(A, B)
INTEGER A, B
MULTIPLY_BY_TWO_INTS = A * B
RETURN
will have a C-style prototype of:
extern int MULTIPLY_TWO_INTS(int *A, int *B);
and you could call it via something like:
int result, a = 1, b = 100;
result = MULTIPLY_TWO_INTS(&a, &b);
Another example are languages that do not know function arguments as such but use stacks. An example would be Forth and its derivatives, where a function can change the variable space (stack) in whichever way it wants, modifying existing elements as well as adding/removing elements. "prototype comments" in Forth usually look something like
(argument list -- return value list)
and that means the function takes/processes a certain, not necessarily constant, number of arguments and returns, again, not necessarily a constant, number of elements. I.e. you can have a function that takes a number N as argument and returns N elements - preallocating an array, if you so like.
How about Brainfuck?