V
6  
Tags
Attachments
Perl 6
Perl 6 Tutorial Part 2


Perl is an operator based language

Unlängst konnte ich herzlich lachen, als ich diesen Satz in der p6l-Mailingliste
sah. Der wahre Kern dieser Pointe besteht darin, daß Perl 6 tatsächlich auffallend
viele Operatoren besitzt und das Operatoren einen bedeutenden Anteil an Perl's
Ausdrucksstärke haben. Und weil Operatoren bereits mit wenig Quellcode angewendet
werden können, eignen sie sich vortrefflich als Einstieg in die Tiefen der Sprache.
Letztlich ist ihre Kenntnis auch eine wichtige Vorraussetzung für spätere,
umfangreichere Beispiele.

Ein wenig Numerik zum aufwärmen

Beginnen wir ganz einfach mit den geläufigsten Operatoren, den Grundrechenarten
('+', '-', '*'), die jeder Insasse dieser Zivilisation vom Grundschullehrer nahe
gebracht bekommt.

Perl 6:
say 3 + 4; # 7
say 3 - 4; # -1
say 3 * 4; # 12

Ebenso zeigte euch der freundliche Mathelehrer auch die Division, Modulo (Rest
einer ganzzahligen Division) und Potenzierung, nur werden die in Computersprachen
etwas anders geschrieben als im Unterricht, da man hier in den alten Tagen auf
den ASCII-Zeichensatz beschränkt war.

Perl 6:
say 3 / 4; # 0.75
say 3 % 4; # 3 ( 3 div 4 = 0 Rest 3 )
say 3 ** 4; # 81 ( = 3 * 3 * 3 * 3 )

Algebra unter erschwerten Bedingungen

So weit erfüllen die Ergebnisse die Erwartungen eines Mathematikers und zeigen,
daß @larry noch wissen, welche Dinge sie besser nicht ändern. Was Mathematiker
jedoch nicht erwarten, aber sehr wohl Perl-Programmierer kennen, die mit Daten
zweifelhafter Herkunft hantieren, sind Zahlenwerte, die Buchstaben enthalten
können. Diese übergeht Perl großzügig, in dem es alles ab dem ersten Zeichen
ignoriert, daß nicht als Zahl interpretiert werden kann. Das wird
Überführung eines Wertes in den numerischen Kontext genannt und geschieht immer
dann, wenn Perl anhand der verwendeten Operatoren erkennt, daß hier mit Zahlen
gerechnet wird. Folgende Beispiele geben gleiche Ergebnisse unter Perl 5 und 6
aus. Die Kommanotation von 'print' hab ich deswegen gewählt, damit die Beispiele
wirklich unter Perl 5 und 6 laufen, da Strings in beiden Sprachen unterschiedlich
zusammengefügt werden.

Perl 5 & 6:
print 3 * '2.2j4',"\n"; # 6.6, da 3 * 2.2
print 3 * 'b2.2j4',"\n"; # 0, da 3 * 0
print - '2.2ah',"\n"; # -2.2, einfache Negierung

Die Unterschiede beginnen, wenn man das '+' als Präfixoperator benutzt.

Perl 5 & 6:
print + '2.3ah',"\n";
print int '2.3ah'; # 2
print abs '-2.4ah'; # 2.4

Während Perl 5 dieses '+' ignoriert, überführt es in Perl 6 den folgenden String
in den numerischen Kontext, wie das '-' in Perl 5 und 6, nur ohne zu negieren.
Zwar gab es bereits in Perl 5 'int', welches ganze Zahlen zurückgibt und 'abs'
das positive Zahlenwerte liefert, aber eine einfache und direkte Umwandlung in
den numerischen Kontext gab es erstaunlicherweise bisher nicht.

Noch mehr Numerik zum vertiefen

Perl 6:
say + '2.3ah'; # 2.3
say - '2.0ah'; # - 2

Diese Beispiele sind es wert, längere Zeit meditativ betrachtet zu werden. Denn
sie beschreiben eine grundlegende Arbeitsweise vieler Operatoren. Perl 6 kennt
nämlich nicht nur Skalar, Array und Hashkontext, sondern noch viele mehr, wie
zum Beispiel den numerischen Kontext. Dessen Symbol ist quasi das '+', welches
diesen nicht nur erzwingt sondern auch Sigil für eine Reihe von Operatoren ist,
die ebenfalls diesen Kontext forcieren. Sie sind bereits als bitverändernde Ops
bekannt, aber äusserlich kaum wiederzuerkennen. Die guten, alten Shiftoperatoren
werden jetzt z.B.'+<' und '+>' geschrieben, wie das nächste Beispiel zeigt. Das
sieht zuerst ungewohnt aus, ist aber logisch, weil meist nur der numerische Wert,
den eine Zeichenkette ausdrückt, für Bitoperationen gebraucht wird. Ausserdem sind
'<<' und '>>' jetzt interpolierende Schwestern der '<' und '>'-Klammern geworden.
So wie "" interpolierende Schwestern von '' sind. Analog zum Erklärten sind die
bitweisen 'und'(and), 'oder'(or) und 'entweder-oder'(xor) nun '+&', '+|' und '+^'.
Die einfachen logischen Operatoren '&', '|' und '^' sind jetzt junktiv. Das werde
ich genauer im Teil 3 erklären, weil es auch den Umgang mit Arrays berührt.

Perl 6:
say 5 +< 2; # 20; 10100 = 101 << 2
say 5 +> 2; # 1; 001 = 101 >> 2
say 5 +& 3; # 1; 001 = 101 & 011
say 5 +| 3; # 7; 111 = 101 | 011
say 5 +^ 3; # 6; 110 = 101 ^ 011

Die meisten sonstigen numerischen Operatoren bleiben wie bekannt, lediglich das
Autoincrement (++) und Autodecrement (--) sind nun keine reinen numerischen Op's
mehr. Bevor ihr einen Herzschlag bekommt: klar verändern sie Zahlenwerte um 1.
Aber sie erzwingen keinen Kontext, sondern passen sich ihm an. Denn sie sind
allgemeine Operatoren geworden, die den Vorgänger oder Nachfolger eines Wertes
rufen und bedienen sich daher des gleichen Mechanismus wie einige Vergleichsops.
Ähnlich brechnen auch 'div' und 'mod' (auf Zahlen angewendet) Division und Modulo,
können sich aber einem anderen Kontext auch anpassen.

Perl 6:
my $a = 5;
say ++$a; # 6 (5 + 1)
say $a++; # 6 (erhöht wird danach)
say --$a; # 6 (6 + 1 - 1)
say $a--; # 6 (verringert wird danach)
say $a --; # Error

Routinierte Perlprogrammierer sollten nicht vergessen, daß jetzt zwischen Variable
und ihrem Präfix- oder Suffixoperator kein Leerzeichen stehen darf. Die Gründe
hab ich im vorigen Teil des Tutorials dargelegt.

Operatoren des Stringkontext

Analog zum numerischen gibt es, wie erwarted, auch einen Stringkontext, dessen
Symbol '~' ist. Warum die Tilde? Nun, weil der ultimative Textoperator '=~' hieß,
also Tilde schon immer etwas mit Strings zu tun hatte und der Punkt, wie letzes
mal schon gezeigt, nun die Objektorientierung ausdrückt. Die Tilde wandelt also
in den Stringkontext um und kann auch Strings verknüpfen, wie der Unixbefehl 'cat',
den es jetzt auch innerhalb von Perl gibt.

Perl 6:
say ~ '2.3ah'; # '2.3ah'
say ~ '2.0'; # '2.0'
say ~ 0xff; # 255
say 'rot ' ~ 'blau' # 'rot blau'
say cat('rot ', 'blau'); # dito
say 'Farbe:' ~ color(); # eine Testausgabe

Die Tilde kann aber auch genauso mit den bitveränderndem Operatoren kombiniert
werden, wie im numerischen Paralleluniversum das Plus. Auch wenn ich bis heute
keinen praktischen Nutzen, für die daraus entstehenden Operatoren gefunden habe,
will ich nicht ausschließen das es einen gibt. Die Tilde signalisiert, daß die
Werte zeichenweise in Ordinalzahlen umgewandelt werden (mit 'ord'). Auf die so
entstandenen Reihen numerischer Werten, können nun die bitweisen Rechenarten
problemlos angewendet werden. Lediglich beim shiften muß der rechte Operand eine
Zahl sein. Die Ergebnisse werden dann selbstverständlich vor der Ausgabe wieder
mit 'chr' in Textzeichen umgewandelt.

Perl 6:
'-' ~< 1 ; #'Z'= chr 90 ( 45 << 1 )
'z' ~> 1 ; #'='= chr 61 ( 122 >> 1 )
'a' ~& 'D'; #'@'= chr 64 (1100001 & 1000100)
'a' ~| 'D'; #'e'= chr 101 (1100001 | 1000100)
'a' ~^ 'D'; #'%'= chr 37 (1100001 ^ 1000100)

Perl 6 kennt aber erfreulicherweise auch die bekannten Befehle zur Bearbeitung von
Zeichenketten wie 'index', 'substr', 'uc', 'lc' und so fort und sogar rubysche
Spielereien wie reverse, welches die Reihenfolge der Zeichenkette umkehrt. Genau
genommen sind das aber eingebaute Funktionen und keine Operatoren, um die es hier
geht. Die bestehen aus wenigen, nicht alphanumerischen Zeichen. Obwohl, das
stimmt eigentlich auch nicht, denn Perl 6 kennt ebenfalls noch das kleine 'x',
mit dem Perlschreiber schon früher Strings vervielfältigten.

Perl 6:
'a' x 5; # 'aaaaa'
'so' x 3; # 'sososo'

Bei wirklich komplexen Fällen, führt jedoch kein Weg an den regulären Ausdrücken
vorbei! Die nennen sich jetzt rules und bieten derart viele Möglichkeiten, daß
sie hier mindestens einen eigenen Teil benötigen. Deswegen folgen jetzt nur wenige
Beispiele um den in Perl 5.10 eingeführten Smartmatchoperator zu demonstrieren.
Dieser ersetzt in Perl 6 das '=~' vollständig.

Perl 6:
"Ich hab getanzt ..." ~~ m/tanz/; # 1
"Ich hab getanzt ..." !~~ m/wanze/; # 1
"Ich hab getanzt ..." ~~ s/tan/schwit/; # Error

Im Gegensatz zu Perl 5 liefert er aber nur einen boolschen Wert zurück, der den
Erfolg der Suche meldet. (Auch beim Ersetzen.) '!~~' negiert am Ende der Suche
lediglich diesen Ergebniswert. Jede weitere Information zum Suchvorgang können
Programmierer wie gewohnt den Spezialvariablen entehmen, deren Syntax sich auch
geändert hat. Die Fehlermeldung im Beispiel ist der Tatsache geschuldet, daß nur
in Variablen, aber nicht in konstanten Ausdrücken ersetzt werden kann.

Vergleichsoperatoren

Die neue Arbeitsweise des '~~' erklärt sich einfach mit dem Umstand, daß es ein
Vergleichoperator wie '==' ist. Der gibt ja auch nur wahr oder falsch zurück.
(im perlschen Sinne) Ohne zu übertreiben kann man sogar sagen, das '~~' der
Endgegner unter den Vergleichsoperatoren ist, noch weit mächtiger als bereits in
Perl 5.10. Je nach Typ und Inhalt seiner Operanden versucht er in jeder Lage
etwas sinnvolles abzuliefern und hat dazu eine große Tabelle, die Vorrang und
Kompatibilität aller internen Perlobjekte zueinander angibt. Das hat von Natur
aus immer etwas mit Unschärfe zu tun und tatsächlich sieht '~~' ein wenig aus,
wie das Symbol für das Wort circacirca.

Das genauer Gegenteil dazu ist der Operator '===', der die Identität, also Inhalt
und Typ zweier Werte vergleicht. Wem das immer noch nicht genau genug ist, kann
noch auf 'eqv' zurückgreifen, welches zusätzlich Laufzeiteigenschaften beachtet.

Perl 6:
1,2 === 1,2; # 0
'3.0' === 3; # 0

Das erste Beispiel ergab negativ, weil es Referenzen (heißen jetzt Captures) auf
2 unterschiedliche Arrays sind. Das zweite ist ebenfalls negativ, weil für Perl
offensichtlich ist, daß der linke Operand ein String ist und der rechte numerisch.

Gewöhnlich entgehen jedoch Perl-Programmierer solchen Problemen, in dem sie auch
beim Vergleich den bevorzugten Kontext erzwingen. Wie in Perl 5 zeigen Ops aus
mathematischen Symbolen ('<','>','<=','>=','==') den numerischen Kontext an.
Vergleichsops aus Buchstaben ('lt','gt','le','ge','eq') vergleichen zeichenweise.

Perl 6:
1,2 == 1,2; # 1
'3.d' == 3; # 1
1,2 eq 1,2; # 1
3.0 eq 3; # 1

Mit anderen Worten: '$a eq $b' ist eine Kurzschreibweise für '~$a === ~$b' und
'$a == $b' kann auch '+$a === +$b' formuliert werden. Was aber tun, wenn nicht
bekannt ist, ob man Zeichen oder Zahlen vergleichen wird? Dann nimmt man '~~',
was aber nur gut gehen kann, wenn beide Vergleichswerte immer noch den gleichen
Typ haben.

Perl 6:
'5' ~~ 5.0; # 1
'du' ~~ 'du'; # 1
3.0 ~~ '3f'; # 0

Die oberhalb aufgezählten Vergleichsops brauchen wohl kaum eine Vorstellung,
auch nicht ihre negierte Form (mit einem '!' davor). Selbst die verkürzten Formen
der 'ungleich'-Operatoren (numerisch '!=' für '!==') und (im string Kontext 'ne'
für '!eq'), haben bereits vor langer Zeit ihren Platz in der Perl-Folklore
gefunden (jeweils beide Schreibweisen sind in Perl 6 erlaubt). Und doch steckt
auch hier eine neue verallgemeinerte Logik hinter diesen Operatoren, denn es gibt
weit mehr sortierbare Dinge als Zahlen und Buchstaben, die man praktischerweise
mit einem Operator befragen kann, ob sie sich in der gewünschten Reihenfolge
befinden. Die Ops dafür sind 'before' und 'after', die leider derzeit noch nicht
von Pugs verstanden werden.

Perl 6:
say 3 before 5; # 1
say 'b' after 'a'; # 1

Somit ist klar, daß '$a > $b' eine andere Schreibart für '+$a after +$b' ist und
'$a lt $b' auch als '~$a before ~$b' ausgedrückt werden kann. All die bisherigen
Vergleichsop haben jedoch gemeinsam, daß sie ein wahr oder falsch liefern. Nun,
eigentlich ist es ein 'Bool::True' oder 'Bool::False', die im normalen, numerischen
Kontext zu 1 oder 0 evaluiert werden, doch heben wir uns diese Spitzfindigkeiten
für später auf, wenn das interne Objektsystem ansteht. Selbst wenn ich mehrere
Vergleiche kombiniere, wie in:

Perl 6:
say 3 < $b < 7; # wird in 1 Zug ausgewertet
say 3 < $b == $b < 7;# in 2 Zügen ausgewertet

erhalte ich einen boolschen Wert, da nur 2 verschiedene Ergebnisse möglich sind.
Im allgemeinen Vergleich sind es jedoch 3: kleiner als, gleich und größer als.
Was sich in den Rückgabewerten, wie in P5, als 1, 0 und 1 ausdrückt. Aber vor
der Umwandlung in den Ergebniskontext ist es ein 'Order::Increase', 'Order::Same'
oder 'Order::Decrease'. Diese und weitere internen Methoden sind auch dafür sehr
nützlich, daß ein Modul wie DateTime sie mit eigenen Routinen überladen kann.
(So etwas wie "Tie" gibt es hier nicht mehr.) Stellt dann der Befehl 'cmp' fest,
daß er hier 2 Objekte vom Typ DateTime vergleichen soll und die Parameterlisten
der bereitgestellten Methoden auch zu den Operanden passen, werden sie verwendet.
Und voila, 'cmp' kann auch Zeitpunkte vergleichen. Ähnlich arbeiten auch '++' und
'-
', die ebenfalls dank mitgelieferter Methoden, Vorgänger- und Nachfolger eines
Objektinhaltes ermitteln können. Jetzt hat mancher Perlkundiger sicher gerufen:
"Aber 'cmp' forciert doch den Stringkontext?". Richtig, in Perl 5, aber nicht in
Perl 6. Hier steht 'cmp' wirklich für 'compare' (vergleiche). Soll beim Vergleich
auf numerischen Kontext geachtet werden, so benutze man das bekannte '<=>', im
Strinkontext allerdings 'leg'. Das hört sich ausgesprochen 'LowerEqualGreater'
an und ist parallel zu <=>, an die Anfangsbuchstaben der Namen der verwandten
Ops 'lt', 'eq', 'gt' angelehnt.

Der dritte Skalarkontext

In diesem Text wurde es schon einige Male unterschwellig erwähnt, Perl 6 kennt
auch einen boolschen Kontext. Und er wird mit dem '?' gefordert, da einfache
Fragen auch meist mit ja oder nein beantwortbar sind. Wie der numerische, so
kennt der boolsche auch einen verneinenden Operator: das Ausrufungszeichen. Eine
Umwandlung in den boolschen Kontext tat man bisher eher implizit, z.B. beim
einsetzen einer Variable in eine if-Bedingung oder in Verbindung mit logischen
Operatoren. Jetzt geht es überall und explizit, auch mit 'true' oder 'not':

Perl 6:
say ? '2.3ah'; # 1
say true 0 ; # 0
say ! '2.3ah'; # ''
say not ''; # 1

Und sicher gibt es hier ebenfalls die kontexterzeugenden Bitoperatoren. Hier macht
es auch ein wenig mehr Sinn als bei Texten. Nur nicht für die Shiftoperatoren,
denn bei einem Bit Registerbreiter, gibt es nichts zu shiften.

Perl 6:
say 0 ?& 'aha'; # 0
say 3 ?| '2.3'; # 1
say '' ?^ 4 ; # 1

Steht das '?^' vor einem einzelnem Operanden, entspricht es einem '!' oder not.

Schlußendlich .. die Auswahloperatoren

Bei den logischen Operatoren gibt es noch eine wohlbekannte Gattung, die den
Kontext der Werte nicht verändert, auch wenn sie intern mit den Umwandlungen der
Werte in den boolschen Kontext rechnet. Ich nenne sie Auswahloperatoren, da sie
den Wert eines Operanden zurückliefern. Manche nennen sie Kurzschlußoperatoren,
da sie vorzeitig abbrechen, wenn das Ergebnis absehbar ist. Das kann man dazu
nutzen, Befehle bedingt ausführen zu lassen. Ich halte meine Bezeichnung für
treffender, da einer aus dieser Gattung (xor), diese Eigenschaft nicht besitzt.
Ihr Syntax wird durch die Wiederholung des logischen Operatorzeichens gebildet.

Perl 6:
say 0 && 'aha'; # 0
say 4 and 0 ; # 0
say 3 || 0 ; # 3
say 0 or 5 ; # 5
say '' ^^ 4 ; # 4
say 7 xor 4 ; # ''

Der mittlere Op hat eine recht neue Variante, die erst Perl 5.10 kennt. Sie nennt
sich defined-or und liefert nur dann den rechten Wert, wenn der linke undefniert
ist. Die 3 Operatoren des letzten Listings haben noch eine Schreibweise, in der
sie mit niedriger Priorität (in einem Ausdruck als Letzte) ausgeführt werden.
('and' statt '&&', or statt '||' und xor statt '^^'). Diese wird gebraucht um
Terme logisch zu verknüpfen, ohne allzuviel Klammern benutzen zu müssen, die die
Lesbarkeit erschweren würden.

Wirklich neu ist in dem ganzen nur das 'orelse'. Es funktioniert exakt wie ein
'or', nur das die Spezialvariable '$!' des linken Blocks, auch im rechten Block
weiterbesteht, falls dieser ausgeführt werden sollte. Dadurch wird dieser Befehl
nützlich, um in knapper Form einen Aufruf oder kleinen Block mit einem zweiten zu
verknüpfen, der im Falle eines Problems, die Fehlermeldung des Ersten auswerten
kann. Entsprechend überträgt andthen $_ in den zweiten Block und führt diesen aus,
wenn der erste erfolgreich war.

Perl 6:
do {...} orelse { say $! }
do {...} andthen { say $_ }

Der wiederum vertraute, ternäre Operator ist nicht direkt ein Auswahloperator,
funktioniert aber ähnlich und wurde auch optisch den Auswahloperatoren angepaßt.
Das war anders kaum möglich, da Fragezeichen, wie bekannt, jetzt den boolschen
Kontext erzwingen.

Perl 6:
$a = defined $b ?? $b !! $c;
$a = $b // $c; # kürzer

Die kaum noch bekannten Flipflopops wurden umbenannt, um Verwechslungen mit den
gleichnamigen Bereichsoperator zu vermeiden ('..' zu 'ff' und '...' zu 'fff').
Dateitestoperatoren wurden den Perl 6-Konventionen angepaßt und werden nun mit
':' statt '-' am Anfang geschrieben. Sie haben auch negierte Versionen (':!')
und können additiv gestapelt aber auch sonstig explizit als Junctions logisch
verknüpft werden.

Perl 6:
if $datei ~~ :e { say 'gibts' }
if $datei.:!e { say 'gabs' }
if $datei :r :w :x { ... }
if $datei :r | :x { ... }

Ich glaube das waren ausreichende Indizien für mein Argument, daß Perl 6 eine
operatorbasierende Sprache ist. Mehr wäre auf einmal auch schwer aufzunehmen.
Die bisher nicht Erwähnten Operatoren , die vor allem Arrays betreffen, wir der
nächste Teil beschreiben.


Previous Chapter | Overview | Next Chapter


 

Upload Files

Click "Browse" to find the file you want to upload. When you click "Upload file" your file will be uploaded and added to the list of attachments for this page.

Maximum file size: 50MB

 
 
 
File Name Author Date Uploaded Size

Save Page As

Enter a meaningful and distinctive title for your page.

Page Title:

Tip: You'll be able to find this page later by using the title you choose.

Page Already Exists

There is already a page named XXX. Would you like to:

Save with a different name:

Save the page with the name "XXX"

Append your text to the bottom of the existing page named: "XXX"

Upload Files

Click "Browse" to find the file you want to upload. When you click "Add file" this file will be added to the list of attachments for this page, and uploaded when you save the page.

 
 
 
Add Tags

Enter a tag and click "Add tag". The tag will be saved when you save the page.

Tag: 

Suggestions: