This code that uses (experimental) macros:
use experimental :macros;
macro new-var() {
quasi {
my $a = 42
}
};
new-var;
say $a
Fails with Variable '$a' is not declared, although the macro passes through without an error. If that's a correct macro declaration, what does it do? If it's not, is there a way to define new variables from within a macro?
The answer from moritz is correct about the state of macros, though from what I know of the work being done in 007, I don't think the program as written would be correct even with a working implementation of Perl 6 macros.
Perl 6 macros will not be textual in nature (C macros are an example of textual ones). A quasi is a quote construct, much like we have quotes for strings and regexes, except that it quotes Perl 6 code, representing it as something AST-ish. (I once would have said that it produces AST, but it's been realized that if an infix were to be interpolated inside of a quasi, then it comes with a precedence and associativity, and we we can't actually form the correct tree for the expression until after interpolation.)
There's a macro concept of "hygiene", whereby symbols declared in the macro body should not, by default, leak out to the place that the macro is applied, since they may well just be implementation details. One would have to explicitly ask to put a symbol into the compiling context where the macro is applied. So I expect the program would have to look like this:
macro new-var() {
quasi {
my COMPILING::<$a> = 42
}
};
new-var;
say $a
Note that this won't work today in Rakudo, although you might find something like it can be made to work in 007.
This might not be the answer you are looking for, but macros in Rakudo are currently really broken. At this point in time I can't even remember if it's supposed to work, or if it's a bug in Rakudo -- it's mostly not worth it figuring it out, because most macro things barely work at all.
This is why Carl Mäsak created 007 to experiment with Macro design outside of Rakudo core, with the goal of eventually bringing the lessons learned back to Rakudo and the Perl 6 language design.
Related
I'm trying to do what a Lisp hacker would call a "symbol macro". To wit, here's what I'm using now:
global ghypers = Dict()
macro hyp(variable, value); ghypers[:($variable)] = :($value); end
macro hyp(variable); ghypers[:($variable)]; end
#hyp foo 5
println(ghypers)
println(#hyp foo)
println(#hyp(foo)+1)
So far so good, but the last thing is ugly, I want to do this:
#foo+1
Sort of like this:
macro foo(); ghypers[:foo]; end
println(#foo)
println(#foo()+1)
Close, and works, but not quite what I wanted, which, again, is:
println(#foo+1)
MethodError: no method matching #foo(::LineNumberNode, ::Module, ::Expr)
Except that that doesn't work.
Lisp has the concept of a symbol macro, where you can bind a macro expansion to a symbol, like foo, so that symbol would expand the to value.
Now, an obvious but equally bad (in the unhygienic sense) way to do this would simply be to bind the global var foo to the value, but I don't want global (or, rather, I want them localized in ghypers).
Is there any way to do the thing I'm seeking in Julia?
(<flame> Having been a happy lisp camper for 40+ years, Julia is the first programming language that I can say I actually like even a little. But not having grok'ed the importance of homoiconicity, their macro system is ... well, to my eyes, quite a mess, where Lisp's is clear as rain water. </flame> :-)
There are two direct ways. If the thing is hygienic and referentially transparent, just use a const value. That won't work in your example.
Otherwise you have to use the macro in call syntax: #foo(). There's no around that, it's how Julia syntax work. Although I won't recommend doing it either.
But a nicer alternative, IMHO, would be an "anaphoric context macro", something like:
#withhyper (stuff) begin
println(foo+1)
end
where foo is a name escaped inside some local scope. Expand the block to a variation of
let foo = setup_hyper(stuff, ...)
println(foo+1)
end
I do not want to write my own recursive-descent math parser or think too deeply about grammar, so I am (re-)using the Perl module Safe.pm as an arithmetic calculator with variables. My task is to let one anonymous web user A type into a textfield a couple of math expressions, like:
**Input Formula:** $x= 2; $y=sqrt(2*$x+(25+$x)*$x); $z= log($y); ...
Ideally, this should only contain math expressions, but not generic Perl code. Later, I want to use it for web user B:
**Input Print:** you start with x=$x and end with z=$z . you don't know $a.
to <pre> text output that looks like this:
**Output Txt:** you start with x=2 and end with z=2.03 . you don't know $a.
(The fact that $a was not replaced is its own warning.) Ideally, I want to check that my web users have not only not tried to break in, but also have made no syntax errors.
My current Safe.pm-based implementation has drawbacks:
I want only math expressions in the first textfield. Alas, :base_math only extends Safe.pm beyond :base_core, so I have to live with the user having access to more than just math algebra expressions. For example, the web users could accidentally try to use a Perl reserved name, define subs, or do who knows what. Is there a better solution that picks off only the recursive descent math grammar parser? (and, subs like system() should not be permitted math functions!)
For the printing, I can just wrap a print "..." around the text and go another Safe eval, but this replaces $a with undef. What I really mean my code to do is to go through the table of newly added variables ($x, $y, and $z) and if they appear unescaped, then replace them; others should be ignored. I also have to watch carefully here that my guys are not working together to try to escape and type text like "; system("rm -rf *"); print ";, though Safe would catch this particular issue. More likely, A could try to inject some nasty JavaScript for B or who knows what.
Questions:
Is Safe.pm the right tool for the job? Perl seems like a heavy cannon here, but not having to reinvent the wheel is nice.
Can one further restrict Safe.pm to Perl's arithmetic only?
Is there a "new symbols" table that I can iterate over for substitution?
Safe.pm seems like a bad choice, because you're going to run the risk of overlooking some exploitable operation. I would suggest looking at a parsing tool, such as Marpa. It even has the beginnings of a calculator implementation which you could probably adapt to your purposes.
I was looking at a rather inconclusive question about whether it is best to use for(;;) or while(1) when you want to make an infinite loop and I saw an interesting solution in C where you can #define "EVER" as a constant equal to ";;" and literally loop for(EVER).
I know defining an extra constant to do this is probably not the best programming practice but purely for educational purposes I wanted to see if this could be done with Perl as well.
I tried to make the Perl equivalent, but it only loops once and then exits the loop.
#!/usr/bin/perl -w
use strict;
use constant EVER => ';;';
for (EVER) {
print "FOREVER!\n";
}
Output:
FOREVER!
Why doesn't this work in perl?
C's pre-processor constants are very different from the constants in most languages.
A normal constant acts like a variable which you can only set once; it has a value which can be passed around in most of the places a variable can be, with some benefits from you and the compiler knowing it won't change. This is the type of constant that Perl's constant pragma gives you. When you pass the constant to the for operator, it just sees it as a string value, and behaves accordingly.
C, however, has a step which runs before the compiler even sees the code, called the pre-processor. This actually manipulates the text of your source code without knowing or caring what most of it means, so can do all sorts of things that you couldn't do in the language itself. In the case of #DEFINE EVER ;;, you are telling the pre-processor to replace every occurrence of EVER with ;;, so that when the actual compiler runs, it only sees for(;;). You could go a step further and define the word forever as for(;;), and it would still work.
As mentioned by Andrew Medico in comments, the closest Perl has to a pre-processor is source filters, and indeed one of the examples in the manual is an emulation of #define. These are actually even more powerful than pre-processor macros, allowing people to write modules like Acme::Bleach (replaces your whole program with whitespace while maintaining functionality) and Lingua::Romana::Perligata (interprets programs written in grammatically correct Latin), as well as more sensible features such as adding keywords and syntax for class and method declarations.
It doesn't run forever because ';;' is an ordinary string, not a preprocessor macro (Perl doesn't have an equivalent of the C preprocessor). As such, for (';;') runs a single time, with $_ set to ';;' that one time.
Andrew Medico mentioned in his comment that you could hack it together with a source filter.
I confirmed this, and here's an example.
use Filter::cpp;
#define EVER ;;
for (EVER) {
print "Forever!\n";
}
Output:
Forever!
Forever!
Forever!
... keeps going ...
I don't think I would recommend doing this, but it is possible.
This is not possible in Perl. However, you can define a subroutine named forever which takes a code block as a parameter and runs it again and again:
#!/usr/bin/perl
use warnings;
use strict;
sub forever (&) {
$_[0]->() while 1
}
forever {
print scalar localtime, "\n";
sleep 1;
};
I'm currently working on a macro/function which I will use as an alternative method to declare lists, namely to use [ and ] instead of the usual '(a b c) way to do it.
Though I'm having some problems, namely that I always have to write quotes before the symbols (as they aren't bound to variables I get an error msg), how would I go about to remove the need for these quotes?
Also, the main reason that I want to introduce this alternative way to declare lists in Common Lisp is because it sometimes tends to be cluttered with parenthesis's and if I actually want to call my function/macro I'll need to enclose it with parens, how would I go about to remove the needs for those?
Thanks!
You can do that with reader macros. (Reader macros are something completely different from "ordinary" macros, by the way.)
However, before you muck around in the readtable, I would strongly recommend that you learn Lisp. Do not fight the parentheses! They are the only syntax you have, so use them!
For learning, I recommend Peter Seibel's "Practical Common Lisp".
This may look like the recent question that asked why Perl doesn't allow one-liners to be "unblocked," but I found the answers to that question unsatisfactory because they either referred to the syntax documentation that says that braces are required, which I think is just begging the question, or ignored the question and simply gave braceless alternatives.
Why does Perl require braces for control statements like if and for? Put another way, why does Perl require blocks rather than statements, like some other popular languages allow?
One reason could be that some styles dictate that you should always use braces with control structures, even for one liners, in order to avoid breaking them later, e.g.:
if (condition)
myObject.doSomething();
else
myObject.doSomethingElse();
Then someone adds something more to the first part:
if (condition)
myObject.doSomething();
myObject.doSomethingMore(); // Syntax error next line
else
myObject.doSomethingElse();
Or worse:
if (condition)
myObject.doSomething();
else
myObject.doSomethingElse();
myObject.doSomethingMore(); // Compiles, but not what you wanted.
In Perl, these kinds of mistakes are not possible, because not using braces with control structures is always a syntax error. In effect, a style decision has been enforced at the language syntax level.
Whether that is any part of the real reason, only Larry's moustache knows.
One reason could be that some constructs would be ambiguous without braces :
foreach (#l) do_something unless $condition;
Does unless $condition apply to the whole thing or just the do_something statement?
Of course this could have been worked out with priority rules or something,
but it would have been yet another way to create confusing Perl code :-)
One problem with braceless if-else clauses is they can lead to syntactic ambiguity:
if (foo)
if (bar)
mumble;
else
tumble;
Given the above, under what condition is tumble executed? It could be interpreted as happening when !foo or foo && !bar. Adding braces clears up the ambiguity without dirtying the source too much. You could then go on to say that it's always a good idea to have the braces, so let's make the language require it and solve the endless C bickering over whether they should be used or not. Or, of course, you could address the problem by getting rid of the braces completely and using the indentation to indicate nesting. Both are ways of making clear, unambiguous code a natural thing rather than requiring special effort.
In Programming Perl (which Larry Wall co-authored), 3rd Edition, page 113, compound statements are defined in terms of expressions and blocks, not statements, and blocks have braces.
Note that unlike in C and Java,
[compound statements] are defined in
terms of BLOCKS, not statements.
This means that the braces are
requried--no dangling statements
allowed.
I don't know if that answers your question but it seems like in this case he chose to favor a simple language structure instead of making exceptions.
Perhaps not directly relevant to your question about (presumably) Perl 5 and earlier, but…
In Perl 6, control structures do not require parentheses:
if $x { say '$x is true' }
for <foo bar baz> -> $s { say "[$s]" }
This would be horrendously ambiguous if the braces were also optional.
Isn't it that Perl allows you to skip the braces, but then you have to write statement before condition? i.e.
#!/usr/bin/perl
my $a = 1;
if ($a == 1) {
print "one\n";
}
# is equivalent to:
print "one\n" if ($a == 1);
"Okay, so normally, you need braces around blocks, but not if the block is only one statement long, except, of course, if your statement would be ambiguous in a way that would be ruled by precedence rules not like you want if you omitted the braces -- in this case, you could also imagine the use of parentheses, but that would be inconsistent, because it is a block after all -- this is of course dependent on the respective precedence of the involved operators. In any case, you don't need to put semicolons after closing braces -- it is even wrong if you end an if statement that is followed by an else statement -- except that you absolutely must put a semicolon at the end of a header file in C++ (or was it C?)."
Seriously, I am glad for every explicitness and uniformity in code.
Just guessing here, but "unblocked" loops/ifs/etc. tend to be places where subtle bugs are introduced during code maintenance, since a sloppy maintainer might try to add another line "inside the loop" without realizing that it's not really inside.
Of course, this is Perl we're talking about, so probably any argument that relies on maintainability is suspect... :)