Let's say I have the following class:
class A {
has $.val;
method Str { $!val ~ 'µ' }
}
# Is this the right way of doing it?
multi infix:<~>(A:D $lhs, A:D $rhs) {
('(', $lhs.val, ',', $rhs.val, ')', 'µ').join;
}
How would I overload an operator (e.g., +) for a class in the same manner as Str in the previous class?
I guess this only works for methods that are invoked on an instance object and using the multi operator-type:<OP>(T $lhs, T $rhs) { } syntax for operators is the right way to go about it but I'm unsure.
For instance, in Python there seems to be a correspondence between special methods named after the operators (e.g., operator.__add__) and the operators (e.g., +). Furthermore, any operator overloading for a custom class is done inside the class.
In Perl 6, operators are considered part of the current language. All things that relate to the current language are defined lexically (that is, my-scoped). Therefore, a multi sub is the correct thing to use.
If putting this code in a module, you would probably also want to mark the multi for the operator with is export:
multi infix:<~>(A:D $lhs, A:D $rhs) is export {
('(', $lhs.val, ',', $rhs.val, ')', 'µ').join;
}
So that it will be available to users who use or import the module (use is in fact defined in terms of import, and import imports symbols into the lexical scope).
While there are some operators that by default delegate to methods (for example, prefix:<+> calls Numeric), there's no 1:1 relation between the two, and for most operators their implementation is directly in the operator sub (or spread over many multi subs).
Further, the set of operators is open, so one is not restricted to overloading existing operators, but can also introduce new ones. This is encouraged when the new meaning for the operator is not clearly related to the normal semantics of the symbol used; for example, overloading + to do matrix addition would be sensible, but for something that couldn't possibly be considered a kind of addition, a new operator would be a better choice.
class A {
has $.val;
method Str { $!val ~ 'µ' }
}
multi infix:<~>(A:D $lhs, A:D $rhs) {
('(', $lhs.val, ',', $rhs.val, ')', 'µ').join;
}
dd A.new(val => "A") ~ A.new(val => "B"); # "(A,B)µ"
So yes, that is the correct way. If you want to override +, then the name of the sub to create is infix:<+>.
You can also provide the case for type objects by using the :U "type smiley", e.g.:
multi infix:<~>(A:U $lhs, A:U $rhs) {
'µ'
}
Hope this answers your question.
Related
This question is in the same ballpark as this other on making blocks iterable, but seems to reveal a different problem with mixins (or a different misunderstanding of the syntax on my part). What Iterable does is to make a data structure effectively iterable, that is, you can create loops by preceding it with for.
Iterable serves as an API for objects that can be iterated with the for construct and related iteration constructs, like hyper operators.
So let's try to put this to practice:
my &logger = -> $event {
state %store;
if ( $event ) {
%store{ DateTime.new( now ) } = $event;
} else {
%store;
}
}
role Forable does Iterable {
method iterator(&self:) {
self( Nil );
}
}
logger( "One" );
logger( "Two" );
&logger does Forable;
.say for &logger;
This simply does not work; say is applied to &logger as a simple item. However, it works if we change that last sentence to:
.say for &logger.iterator;
Which I guess that indicates that the role is actually working, and mixed in. Since the type for &logger is Block+{Forable}, maybe it does not work if Iterable is not mixed in directly. In fact, erasing does Iterable from the Forable declaration does not affect it in any way. Let's try then this:
&logger does (Iterable,Forable);
Now the type of &logger is revealed as Block+{Iterable,Forable}, but still no joy. iterator has to be called directly. Any idea on how to solve this?
I don't think you can. The basic problem is that &foo (the Callable object) and foo() (calling the Callable object) are two very different things.
Feels to me you're trying to add a method to a class, but you're working with a Sub.
You need to mixin the iterator method on the return value of logger. As I don't really understand what you're trying to achieve, it's hard to answer the question.
Looking at the result that you apparently want to achieve, I came up with this:
my %store;
multi sub logger() {
%store
}
multi sub logger($event) {
%store{ DateTime.new( now ) } = $event;
}
logger( "One" );
logger( "Two" );
.say for logger;
But that doesn't use roles at all. So that may not be what you're going for.
When does for call the iterator method?
As I understand, if the (single) argument to an iterating feature is a Scalar container, then it uses the value in the container and does not call .iterator. Otherwise, it calls .iterator on it, evaluating it first if it's an expression or routine call.
&logger does Forable;
.say for &logger;
This simply does not work; say is applied to &logger as a simple item.
The & is a noun marker (sigil) marking a Callable that is inherently a single thing, a single block of code.
More specifically, &logger is bound to a Scalar container whose type is Callable, exactly the same as $logger (with a $ sigil) would be if you wrote my Callable $logger:
say .WHAT, .VAR, .VAR.WHAT, .VAR.of
for my &logger, my Callable $logger
displays:
(Callable)Callable(Scalar)(Callable)
(Callable)Callable(Scalar)(Callable)
Since the type for &logger is Block+{Forable}
That's actually the type of the Callable that's contained in the Scalar container that's bound to &logger.
It's not the type of the &logger container itself, which is a Scalar, as shown above.
When given a single argument in the form of a variable, iterating features like for look at the variable, not the value contained in the variable, to see if it's Iterable. A Scalar is not Iterable.
Any idea on how to solve this?
See lizmat's answer for one approach.
Question Updated
I have list of (few more) regex patterns like: (Note: Sequence is very Important)
([a-z]+)(\d+)
\}([a-z]+)
([a-z]+)(\+|\-)
([0-9])\](\+|\-)
...
...
my input file like :
\ce{CO2}
\ce{2CO}
\ce{H2O}
\ce{Sb2O3}
...
...
In my code I am finding the each and every regex patterns like
if($string=~m/([a-z]+)(\d+)/g) { my statements ... }
if($string=~m/\}([a-z]+)/g) { my statements ... }
if($string=~m/([a-z]+)(\+|\-)/g) { my statements ... }
if($string=~m/([0-9])\](\+|\-)/g) { my statements ... }
Instead of doing the above code Is there any other way to simplify the code?
Could you someone please share your thoughts for my improvement for better coding.
Disclaimer: Your question is very hard to read, so this is pretty much guesswork. I am not sure I understand what you want to do.
When you are processing data in a dynamic way, a typical approach is to use a dispatch table. We can do something similar here. Often a hash or hash reference is used for that, but since we want a specific order, I will be using an array instead.
my #dispatch = (
{
pattern => qr/f(o)(o)/,
callback => sub {
my ($one, $two) = #_;
print "Found $one and $two\n";
},
},
{
pattern => qr/(bar)/,
callback => sub {
my $capture = shift;
print "Saw $capture";
},
},
);
This basically is a list of search patterns and associated instructions. Each pattern has a callback, which is a code reference. I decided it would make sense to pass in the capture variables, because your patterns have capture groups.
Now in order to call them, we iterate over the dispatch array, match the pattern and then call the associated callback, passing in all the captures.
my $text = "Foo bar foo bar baz.";
foreach my $search (#dispatch) {
if ($text =~ $search->{pattern}) {
$search->{callback}->(#{^CAPTURE}); # this requires Perl 5.26
}
}
Please note that I am using #{^CAPTURE}, which was added to Perl in version 5.25.7, so you would require at least the stable Perl 5.26 release to use it. (On an older Perl, my #capture = $t =~ $search->{pattern} and $search->{callback}->(#capture) will behave similarly).
This is way more elegant than having a list of if () {} statement because it's very easy to extend. The dispatch table could be created on the fly, based on some input, or entirely read from disk.
When we run this code, it creates the following output
Found o and o
Saw bar
This is not very spectacular, but you should be able to adapt it to your patterns. On the other hand I don't know what you are actually trying to do. If you wanted to modify the string instead of only matching, you might need additional arguments for your callbacks.
If you want to learn more about dispatch tables, I suggest you read the second chapter of Mark Jason Dominus' excellent book Higher Order Perl, which is available for free as a PDF on his website.
Your question is hard to read, mainly because you have the /g at the end of your regex searches (which returns a list), however, you only check if it matches once.
I'm making the following assumptions
All matches are required
the code can be a single or double match
both groups captured in one line
i think you want
while ( $string =~ /(([a-z]+)(\d+)|\}([a-z]+)|([a-z]+)(\+|\-)|([0-9])\](\+|\-))/g )
{
#$1 has the whole match
#$2 has the first group if defined
#$3 has the second group if defined
}
However, I prefer the method below. this will capture in one line
while ($string =~ /([a-z]+\d+|\}[a-z]+|[a-z]+\+|\-|[0-9]\]\+|\-)/g )
{
# in here split the match if required
}
I recommend you use regex comments to make this clearer.
if you just want a single match, use
if(
$string=~m/([a-z]+)(\d+)/ ||
$string=~m/\}([a-z]+)/ ||
$string=~m/([a-z]+)(\+|\-)/ ||
$string=~m/([0-9])\](\+|\-)/
)
{
#some code
}
Is it possible to write a macro that expands an expression into multiple indexed arguments, which can be passed to a function or another macro?
See this simple self contained example.The aim is to have unpack3 expand v into v[0], v[1], v[2].
macro_rules! elem {
($val:expr, $($var:expr), *) => {
$($val == $var) || *
}
}
// attempt to expand an array.
macro_rules! unpack3 {
($v:expr) => {
$v[0], $v[1], $v[2]
}
}
fn main() {
let a = 2;
let vars = [0, 1, 3];
// works!
if elem!(a, vars[0], vars[1], vars[2]) {
println!("Found!");
}
// fails!
if elem!(a, unpack3!(vars)) {
println!("Found!");
}
}
The second example fails, is it possible to make this work?
Possible solutions could include:
Changing use of macro grammar.
Using tuples, then expanding into arguments after.
Re-arranging the expressions to workaround macro constraints.
Note, this may be related to Escaping commas in macro output but don't think its a duplicate.
This is impossible in two different ways.
First, to quote the answer to the question you yourself linked: "No; the result of a macro must be a complete grammar construct like an expression or an item. You absolutely cannot have random bits of syntax like a comma or a closing brace." Just because it isn't exactly a comma doesn't change matters: a collection of function arguments are not a complete grammar construct.
Secondly, macros cannot parse the output of other macros. This requires eager expansion, which Rust doesn't have. You can only do this using recursion.
I'm reading this fantastic introduction to Perl6 and came across a rather interesting term:
Note the ! twigil means “this is private to the class”.
class ScoreKeeper {
has %!player-points;
}
I know what sigils are in Perl5. But what's a twigil?
Is it just a fancy way to say that there are two sigils prepending the attribute/variable name?
The design documents S02 and S99 both talk about twigils. (Emphasis mine).
Ordinary sigils indicate normally scoped variables, either lexical or
package scoped. Oddly scoped variables include a secondary sigil (a
twigil) that indicates what kind of strange scoping the variable is
subject to: [...]
So it is a secondary sigil or rather a second sigil. Declaring $*foo will not declare $foo.
my $*foo = 1;
say $foo;
This will yield Variable '$foo' is not declared at....
It seems to be related to variable scoping:
Twigils influence the scoping of a variable...
Twigil Scope
------ ----------------------------------------------
none Based only on declarator
* Dynamic
! Attribute (class member)
? Compile-time variable
. Method (not really a variable)
< Index into match object (not really a variable)
^ Self-declared formal positional parameter
: Self-declared formal named parameter
= Pod variables
~ The sublanguage seen by the parser at this lexical spot
http://docs.raku.org/language/variables#Twigils
From the documentation on twigils:
Attributes are variables that exist per instance of a class. They may be directly accessed from within the class via !:
class Point {
has $.x;
has $.y;
method Str() {
"($!x, $!y)"
}
}
Note how the attributes are declared as $.x and $.y but are still accessed via $!x and $!y. This is because in Perl 6 all attributes are private and can be directly accessed within the class by using $!attribute-name. Perl 6 may automatically generate accessor methods for you though. For more details on objects, classes and their attributes see object orientation.
Public attributes have the . twigil, private ones the ! twigil.
class YourClass {
has $!private;
has #.public;
# and with write accessor
has $.stuff is rw;
method do_something {
if self.can('bark') {
say "Something doggy";
}
}
}
I'm going to write an inferrer for my dsl and I have some questions that I could not solve with only the help of documentation.
First one:
I need to create static void main() from a feature: how can I add static with .toMethod()?
Second one:
Suppose I have a rule in my dsl like this:
Sequence:
'SEQ' name=ID '{'
statements+=Statement*
'}'
;
Where Statement:
Statement:
Sequence | others...
;
Sequence must be mapped to a void method and the body of that method is composed from the traslation of statements.
But the problem is this: when inside a Sequence I'll find another Sequence I have to create a method for the new sequence and add a call in super sequence.
For example:
SEQ first {
instructions...
SEQ second {
other instructions....
}
instructions...
}
Must generate:
void first(){
instructions(translated)...
second();
instructions(translated)...
}
void second(){
other instructions(translated)...
}
Is it possible to realize it?
First question:
ctx.toMethod('main', ctx.newTypeRef(Void.Type)) [
static = true
….
]
Second question:
Implying that with 'instructions' you mean instances of 'XExpression', you need to trick a bit, as it is currently not possible to compose new expressions during inference.
What you coudl basically do is to make your Sequence a subtype of XExpression. Then during JvmModelInference you need to walk over your expression tree (Statement) and create methods for Sequences. you need to override the XbaseTypeComputer as well as the XbaseCompiler and add type computation and compile strategies for your expressions. The latter would be a call to the method created during inference.