Tuesday, May 22, 2007

Perl 6: Round 1

Pugs revision: r16464

Note: Oh, before we get started, a quick word I probably should have addressed in my last post: it'd be good to note by anybody reading this blog, that the face of Perl 6 can change pretty quickly. Code may work one day and not the next. It is therefore important not to focus entirely on the syntax of the code: the scales tilt better in favor of semantics than syntax. But just know, semantics are subject to change as well (although I hope to get the general point across.)
It will, therefore, not be my responsibility to update the code to reflect future changes to Perl 6 and Pugs. What you read here should be taken with a grain of salt and it may not work out of the box for you. For this reason, I'm going to start posting the revision number of my Pugs version at the top of my blogs (such as seen starting with this post; note that if I decide to deal with the v6.pm Perl5 module, I will state so explicitly), so you can get an idea of the 'when and where this worked.' This isn't a solid metric; it is merely suggestive.
Essentially, be warned: frustration may lie within.

So now that such a formality is out of the way (albeit, an important one,) let's go!


Starting off
I'm sure you're as ready as I am to get hacking with Perl 6. Let's start by doing some simple evaluations in Pugs:

[altair@stormwind perl6]$ pugs
______
/\ __ \
\ \ \/\ \ __ __ ______ ______ (P)erl 6
\ \ __//\ \/\ \/\ __ \/\ ___\ (U)ser's
\ \ \/ \ \ \_\ \ \ \/\ \ \___ \ (G)olfing
\ \__\ \ \____/\ \____ \/\_____\ (S)ystem
\/__/ \/___/ \/___/\ \/____/
/\____/ Version: 6.2.13 (r16464)
\/___/ Copyright 2005-2007, The Pugs Contributors
--------------------------------------------------------------------
Web: http://pugscode.org/ Email: perl6-compiler@perl.org

Welcome to Pugs -- Perl6 User's Golfing System
Type :h for help.

Loading Prelude... done.
pugs> "Good to see you, my friend"
"Good to see you, my friend"
pugs> 1
1
pugs> 1 + 2
3
pugs> 2**5
32/1
pugs>

The pugs prompt essentially is to Perl 6 as GHCi is to Haskell: Expressions are evaluated in the prompt and pugs will give you the overall result of your expression. Any arbitrary expression may be entered into the prompt providing it is syntactically and/or semantically correct.

An interesting point to note here is the absence of a semicolon in our statements: an expression sans a semicolon in the pugs prompt will evaluate the expression, and give us the overall value of the expression, i.e. the return value, with or without side effects (such as I/O.) A semicolon in the above statements would result in nothing being outputted: the return value is computed, but not printed to standard output.
This is a good point to know; absence of a semicolon in your expressions will give you the result of the expression as far as pugs itself is concerned, i.e. it may tell you True, undef, or it may even return the 'de-sugared' form of an object. A semicolon at the end essentially just 'mutes' your output a little (as far as this introductory tutorial goes.)


Also note that types in Perl 6 are strictly optional. Like it's predecessors, Perl 6 is dynamically typed; however, a type system does exist now: type annotations to specify what a variable is/holds are strictly optional, however.
In perl 6, there are two distinct different types: Mutable types, and Immutable types (Note: these definitions are fairly lax. For a stricter definition, you should refer to S02.) Mutable types are essentially the type a variable actually is, as opposed to what it contains. These types include Scalar, Array, Hash, Sub, etc. etc.. Immutable types are are the other half: the type a variable may contain. These are types such as Str, Int, Complex, and Bool.

Now, we'll continue. It's only proper to do a 'hello world' in a language when you first start it. Let's do that now:

pugs> say "hello world";
hello world
pugs>


On a side note, one of the newer things about Perl 6 is that many of the builtin functions act a lot like method's of a class; the above example could have been written this way as well:

pugs> "hello world".say;
hello world
pugs>


This will work with just about any builtin function (see: S29.) The syntactical choice is merely personal preference.

At the point when writing anything really significant, we should probably get out of Pugs itself. We can simply write the code in a source file and execute like so:

[altair@stormwind diveintoperl6]$ cat > hello.p6
use v6;

say "hello world";
[altair@stormwind
diveintoperl6]$ pugs hello.p6
hello world
[altair@stormwind
diveintoperl6]$

We will continue to use Pugs in the prompt until we are to the point that we would rather have a script.

Variables in general

In Perl 6, you stand beside your tried and true variable types. You've still got your scalar & co.. There is a difference in Perl 6 though that needs to be addressed now, this difference being sigil invariance. Sigil invariance in Perl 6 means, that while your variable sigil's changed depending on context in Perl 5, they do not in Perl 6. You will always refer to @arr as @arr, i.e.

my @arr = (1,2,3,4,5);
say @arr[1]; #this will output 2


This goes for all the basic variables in Perl 6. (Given, you can create a scalar that's a reference to an array, thus getting the same effect.)

Also, you must always explicitly define your variables in Perl 6 using 'my.' To go without it will produce an error.
(edit 05/25/07: the above is not entirely correct; in perl 6, a 'use strict;' declaration is implied in code and is the default; thanks to Aankhen`` for pointing this out.)

Scalar
A scalar is a variable in the most basic sense. It holds a single value of whatever you want. For example, an integer, a string, a reference, etc. etc..

To be completely honest, there isn't much to say here. So I'll just move forward.

Array
An array is simply a list of Scalar values, to put it bluntly. Array's can hold an arbitrary number of elements of any arbitrary type.

Declaring an array is as simple as a comma delimited list of elements, as such:

@a = (1,2,3,4,5);
@b = ('a','b','c','d','e');


They can also be declared 'word style' using the < > operators:

@a = <1 2 3 4 5>;
@b = <a b c d e>;


These operators in this context act much like the perl 5 construct qw(). They create an array based on the string, token delimited by any amount of whitespace (you may also use these with hashes as we'll see later.) Note that using this style, your array value's will in terms of type, be strings. However, Perl is dynamic, so s'all good baby.

Array's have several functions dedicated to them. Let's play around.

pugs> my @a = ("this","is","my","house");
pugs> @a.pop
"house"
pugs> @a.shift
"this"
pugs> @a.unshift("hi")
3
pugs> @a
("hi", "is", "my")
pugs> @a.push("whoa")
4
pugs> @a
("hi", "is", "my", "whoa")
pugs>


It's important to know these functions cause, what's known in the Haskell world, as a destructive update. The actual array is modified your function (a side effect); you must be aware of this.

Hashes
A hash is essentially the same as it was in Perl 5. A hash is an array of key => value pairs. Rather than using a numerical index into a hash, you can instead use a textual index. Let's see an example:

pugs> my %h = ("five" => 5, "my_name" => "austin seipp", "delta" => 3.14);
pugs> %h{"five"}
5
pugs> my $d = "delta";
pugs> %h{$d}
157/50
pugs> %h<my_name>
"austin seipp"
pugs>


Hash elements are referenced using a key, this key can be passed the traditional way via the { }brackets with the quoted string/variable, or you may use the < > brackets now to achieve the same effect, i.e.:
pugs> %h<delta>
157/50
pugs>

Hashes have several operations of their own. Examples:

pugs> %h.keys
("my_name", "five", "delta")
pugs> %h.elems
3
pugs> %h.values
(157/50, 5, "austin seipp")
pugs> %h.kv
("my_name", "austin seipp", "five", 5, "delta", 157/50)
pugs>



These our are basic variables; be sure to look at S29 for function references and play around with a lot of the built in variable types and their functions.

Control Structures
Perl 6, for the most part, has similar control structures to that of Perl 5. You have your traditional if and while loops, i.e:
pugs> if $a {
....> say "cool!";
....> } else {
....> say "uncool!";
....> }
cool!
Bool::True
pugs> my $b = 1;
pugs> while ($b++ != 10) {
....> say "still even cooler!";
....> }
still even cooler!
still even cooler!
still even cooler!
still even cooler!
still even cooler!
still even cooler!
still even cooler!
still even cooler!
still even cooler!
undef
pugs>

Pretty basic, as you can see. You also have an unless statement, which essentially is just the opposite of if. There are also a couple of (slightly) different control structures; namely for, loop, and given.

For is basically the equivilant to an array iterator control structure (commonly known as foreach in other cultures), example:

pugs> my %h = ("key1" => 1, "key2" => 2, "key3" => 3);
pugs> for %h.kv -> $k,$v {
....> say "Key: " ~ $k ~ "\t Value: " ~$v;
....> }
Key: key1 Value: 1
Key: key2 Value: 2
Key: key3 Value: 3
undef
pugs>

Loop is basically the canonical for in other languages. It is called with the traditional syntax of loop ($i=0;$i<10;$i++) you would generally see in other languages.

However, with no arguments, loop can also be used as a simple infinate loop. Example:

[altair@stormwind diveintoperl6]$ cat > loop.p6
loop {
say "i'm never going to terminate, ever!";
}
[altair@stormwind diveintoperl6]$ pugs loop.p6
i'm never going to terminate, ever!
i'm never going to terminate, ever!
i'm never going to terminate, ever!
i'm never going to terminate, ever!
i'm never going to terminate, ever!
i'm never going to terminate, ever!
i'm never going to terminate, ever!
i'm never going to terminate, ever!
i'm never going to terminate, ever!
i'm never going to terminate, ever!
...
^C goingpugs: interrupted
[altair@stormwind diveintoperl6]$


Loops also have means of breaking out of loops, the same way you would use continue; or break; in other languages. These means are the keywords next,redo and last. next and last are essentially the same as continue or break (continue exists in perl 6 too, we'll get to that in a moment.) redo is a little different, essentially it is the same as next, only no counters are iterated and the loop simply starts over in the same state.

Here's another example:

pugs> my $i = 0;
pugs> loop {
....> $i++;
....> last if $i == 10;
....> next if $i == 5;
....> redo if $i == 8;
....> say "iterator: "~$i;
....> }
iterator: 1
iterator: 2
iterator: 3
iterator: 4
iterator: 6
iterator: 7
iterator: 9
undef
pugs>


In this instance, redo essentially does the exact same as next; it is important to note that in this case, our differentiator ($i) is being modified inside the context of loop, so therefore -- as far as this example goes -- redo doesn't really accomplish much. redo is useful however when for example, you want a condition to be held and not continue to the next iteration without that condition being true (for example, you need a sub that is called in your loop to return True in order to continue with the next iteration of the loop.) This condition would most likely be dependent on some sort of a side effect (such as say an external file modification, or even another thread.) Here's a basic example:
[altair@stormwind diveintoperl6]$ cat > redo.p6
#!/usr/src/env pugs
use v6;

sub blocker { ... }

loop (my $i=0;$i<5;$i++) {
say 'iteration: '~$i;
redo unless blocker();
}

my $j = 0;
sub blocker {
($j++ < 3) ?? True !! False;
}
[altair@stormwind diveintoperl6]$


(edit 05/29/07: redo is apparently not fully implemented, as tested on pugs r16525.)

The final control structure I'll describe here is given; essentially, given == switch if ($lang == 'Perl 6'). For anybody who's been wishing for a switch for perl: you've finally got it. Example:

pugs> my $i = "str1";
pugs> given $i {
....> when "str1" {
....> say "we have str1 in our midst";
....> }
....> when "str2" {
....> say "str2 is alive!";
....> }
....> default {
....> say "default case, too bad";
....> }
....> }
we have str1 in our midst
Bool::True
pugs>

It's important to note that, all of the when cases inside of a given have an implicit break on the end. You may fall through to the next structure however, using an explicit continue in your particular when case.

given can be used in a little more advanced manner (notably with rules,) but we'll probably move onto that in later articles.

Conclusion

This article is the first part in a few series I'll be making to introduce people to the language. At the end of these 'Rounds,' we'll get to actually writing production code and a few programs in Perl 6.

Exciting, isn't it?

5 comments:

Christ Chex said...

Sure is exciting! Keep up the posts, I sincerely appreciate it!

Anonymous said...

You should know that on the planet perl6 website all your "<" characters have disappeared for some reason.

Anonymous said...

Hey, I normally don't leave comments but I just thought I'd let you know that this blog is great. I write too, but I can't
write as well as you do. Here are some of my writings. If you want to look at them, if not it's ok. anyway, thanks.

Warcraft Powerleveling Guides
Assassin's Creed 2 Review
How To Play Magic The Gathering

Anonymous said...

Hey. I don't normally leave comments, but I just wanted to say thanks for the great information. I have a blog too, though
I don't write as good as you do, but if you want to check it out here it is. Thanks again and have a great day!

Stihl Chain Saws

Anonymous said...

top [url=http://www.c-online-casino.co.uk/]casino online[/url] coincide the latest [url=http://www.casinolasvegass.com/]online casinos[/url] manumitted no consign hand-out at the chief [url=http://www.baywatchcasino.com/]no put bonus
[/url].