Bu belge, Raku programlama dili hakkında genel bir bakış sunması amacıyla hazırlanmıştır. Yeni olanlar için hızlı bir başlangıç olacaktır.

Bu belgenin bazı bölümleri Raku dökümantasyonu'na değinmektedir. Belirli bir konuda daha fazla bilgiye ihtiyacınız varsa bunları okumalısınız.

Belge boyunca tartışılan konuların örneklerini bulacaksınız. Örneklerden daha iyi yararlanmak için örnekler üzerine zaman ayırın ve kendi örneklerinizi oluşturmaya çalışın.

Lisans

Bu eser Creative Commons Atıf-AynıLisanslaPaylaş 4.0 Uluslararası Lisansı uyarınca lisanslanmıştır. Bu lisansın bir kopyasını görüntülemek için aşağıdaki adresi ziyaret edin

Katkı

Bu belgeye katkıda bulunmak isterseniz:

Geri Bildirim

Tüm görüşeriniz memnuniyetle karşılanmaktadır:

Bu eseri beğendiyseniz, kaynağına göz atabilirsiniz Github.

1. Giriş

1.1. Raku Nedir?

Raku yüksek seviyeli, genel amaçlı, kademeli yazılan(gradually typed) bir dildir. Raku prosedürel, nesne yönelimli ve fonksiyonel programlamayı destekler. (multi-paradigmatic)

Raku mottoları:
  • TMTOWTDI (Tim Toady şeklinde telaffuz edilir.): Bir şeyi yapmanın birden fazla yolu vardır. -There is more than one way to do it.

  • Kolay şeyler kolay olmalı, zor şeyler kolaylaştırılmalı ve imkansız şeyler zorlanmalı. -Easy things should stay easy, hard things should get easier, and impossible things should get hard.

1.2. Jargon

  • Raku: Perl programlama dili ailesinin bir üyesidir. Bir dil belirtimi ile test paketi içerir. Belirtim test paketini geçen uygulamalar Raku olarak kabul edilir.

  • Rakudo: Raku derleyicisidir.

  • Rakudobrew: Rakudo kurulum yöneticisidir.

  • Zef: Raku modül yöneticisidir.

  • Rakudo Star: Rakudo, Zef, Raku modül koleksiyonu ve dökümantasyonu içeren pakettir.

1.3. Raku Kurulumu

Linux

Rakudo Star kurulumu için komutları takip edin:

mkdir ~/rakudo && cd $_
curl -LJO https://rakudo.org/latest/star/src
tar -xzf rakudo-star-*.tar.gz
mv rakudo-star-*/* .
rm -fr rakudo-star-*

./bin/rstar install

echo "export PATH=$(pwd)/bin/:$(pwd)/share/perl6/site/bin:$(pwd)/share/perl6/vendor/bin:$(pwd)/share/perl6/core/bin:\$PATH" >> ~/.bashrc
source ~/.bashrc

Diğer ayarlar için https://rakudo.org/star/source adresini ziyaret edebilirsiniz.

macOS

Dört seçenek mevcuttur:

  • Linux’a yüklemek için gereken adımları takip edin.

  • Homebrew ile kurulum için: brew install rakudo-star

  • MacPorts ile kurulum için: sudo port install rakudo

  • Son çıkan kurulum dosyasını(.dmg) indirmek için: https://rakudo.perl6.org/downloads/star/ adresini ziyaret edin.

Windows
  • Son kurulum dosyasını(.msi) indirin, eğer sisteminiz 32-bit ise x86 dosyasını, 64-bit ise x86_64 dosyasını: http://rakudo.org/how-to-get-rakudo/ adresini ziyaret edin.

  • Eğer kurulum sırasında PATH’e ekleme seçeneğini seçmediyseniz, kurulum sonrasında C:\rakudo\bin yolunu PATH’e eklemeniz gerekir.

Docker
  • Resmi Docker imajını edinin: docker pull rakudo-star

  • Konteynırı çalıştırmak için: docker run -it rakudo-star

1.4. Raku Kodunun Çalıştırılması

Raku’nın REPL(Read-Eval-Print Loop) üzerinden çalıştırılması için terminali açıp perl6 yazmanız ve [Enter]'a basmanız yeterli. Herşey yolunda giderse > işareti ile terminalin sizden giriş beklediğini görmelisiniz. Eğer bir hatayla karşılaşırsanız kurulum bölümüne geri dönmelisiniz. REPL’dan çıkmak için exit yazmanız ve [Enter]'a basmanız şimdilik yeterli.

Raku kodunu çalıştırmanın alternatif bir yöntemi ise herhangi bir editörle yazdığımız kodu uzantısı .pl6 olacak şekilde kaydederek terminale perl6 dosyaismi.pl6 yazmanız ve [Enter]'a basmanızdır. Burada önemli olan nokta dosya ile aynı dizinde olmanızdır ve eğer kodunuz bir çıktı üretmiyorsa ekranda bir şey göremezsiniz.

Farklı bir yöntem ise tek satırlık komutlardır. Tek satırlık kodlar çalıştırmak için perl6 -e 'kodunuz' şeklinde kullanılması gerekir.

Eğer Rakudo Star paketini kurmadıysanız, REPL üzerinde sağ veya sol ok tuşlarının farklı çalıştığını görebilirsiniz, bu REPL’den yararlanmamızı zorlaştıracaktır.

Bu durumda yardımcı olacak bir satır düzenleyicisi için:

  • zef install Linenoise Windows, Linux ve macOS üzerinde çalışmaktadır.

  • Linux üzerindeyseniz zef install Readline modülünü tercih edebilirsiniz.

1.5. Editörler

Çoğu zaman, Raku programlarmızı dosyalara yazıp depolayacağımız için, Raku sözdizimini tanıyan iyi bir metin editörüne sahip olmalıyız. Birçok alternatif bulunduğundan biz sadece ikisine değineceğiz. * Modern bir metin editörü olan Atom ve Raku Language Highlighter Perl 6 FE eklentisi. * Diğer editörlere Vim, Emacs Padre adreslerinden ulaşabilirsiniz.

Bu editörlerden herhangi birisini kullanabilirsiniz.

1.6. Merhaba Dünya!

Merhaba Dünya ritüelini yerine getirerek başlayalım.

say 'Merhaba Dünya';

Ayrıca şu şekilde de yazılabilir:

'Merhaba Dünya'.say;

1.7. Söz Dizimine Genel Bakış

Raku çoğu zaman düzensiz çalışmanıza izin verir.

Her bir ifade, genellikle mantıksal bir kod satırıdır ve noktalı virgülle bitmesi gerekir: say "Merhaba" if True;

İşlemler değer döndürürler: 1+2 ifadesi 3 değerini döndürür.

İfadeler koşul ve operatörlerden oluşur.

Koşullar:

  • Değişkenler: Manipüle edilebilir ve değiştirilebilir bir değer.

  • Sabitler: Bir sayı veya karakter dizisi gibi sabit bir değer.

Operatörler tiplerine göre sınıflandırılır:

Tip

Açıklama

Örnek

Önek(Prefix)

Terimden önce

++1

Bağlama(Infix)

Terimler arasında

1+2

Sonek(Postfix)

Terimden sonra

1++

Başında ve sonunda(Circumfix)

Terimin etrafında

(1)

Sonrasında, başında ve sonunda(Postcircumfix)

Terimin öncesinde ve etrafında

Array[1]

1.7.1. Tanımlayıcılar

Tanımlayıcı, tanımlanan veriye verilen isimdir.

Rules:
  • Alfabetik bir karakter veya alt çizgi ile başlamalıdırlar.

  • İlk karakter hariç rakamlar içerebilirler.

  • İlk ve son karakter hariç tire veya kesme işareti içerebilir. Yani her tire veya kesme işaretinin sağ tarafında alfabetik bir karakter olmalı.

Geçerli

Geçersiz

var1

1var

var-one

var-1

var’one

var'1

var1_

var1'

_var

-var

Adlandırma Kuralları:
  • Camel Case: degerNo1

  • Kebab Case: deger-no1

  • Snake Case: deger_no1

Tanımlayıcılarınızı istediğiniz gibi adlandırmakta serbestsiniz ancak sürekli aynı kuralı kullanmak iyi bir huydur.

Anlamlı isimler kullanmak sizin ve kodu okuyanların anlamasını kolaylaştıracaktır. Örneğin:

  • var1 = var2 * var3 söz dizimsel açıdan doğrudur, ancak amacı açık değildir.

  • monthly-salary = daily-rate * working-days gibi bir kullanım değişken isimlendirmede daha iyi bir yöntemdir.

1.7.2. Yorumlar

Yorumlar derleyici tarafından yok sayılır ve not olarak kullanılırlar.

Yorumlar üç tipe ayrılmışlardır:

  • Tek satırlık yorumlar:

    # Bu tek satırlık bir yorumdur
  • Gömülü yorumlar:

    say #`(Bu gömülü bir yorumdur.) "Merhaba"
  • Çok satırlı yorumlar:

    =begin yorum
    Bu bir çok satırlı yorumdur.
    Yorum 1
    Yorum 2
    =end yorum

1.7.3. Tırnak İşareti

String veri tipinin tek veya çift tırnak işareti ile sınırlandırılması gerekir.

Çift tırnak kullanılması gereken durumlar:

  • Karakter diziniz kesme işareti içeriyorsa.

  • İşleme tabii tutulması gereken bir değişken içeriyorsa.

Örneğin:

say 'Hello World';   # Hello World
say "Hello World";   # Hello World
say "Don't";         # Don't
my $name = 'John Doe';
say 'Hello $name';   # Hello $name
say "Hello $name";   # Hello John Doe

2. Operatörler

2.1. Yaygın Operatörler

Aşağıdaki tabloda sık kullanılan operatörler listelenmiştir.

Operator Type Description Example Result

+

Bağlama(inflix)

Ekleme

1 + 2

3

-

Infix

Çıkarma

3 - 1

2

*

Infix

Çarpma

3 * 2

6

**

Infix

Kuvvet

3 ** 2

9

/

Infix

Bölme

3 / 2

1.5

div

Infix

Tam sayı bölme

3 div 2

1

%

Infix

Modül

7 % 4

3

%%

Infix

Bölünebilirlik

6 %% 4

False

6 %% 3

True

gcd

Infix

En büyük ortak bölen

6 gcd 9

3

lcm

Infix

En küçük ortak kat

6 lcm 9

18

==

Infix

Numerik eşitlik

9 == 7

False

!=

Infix

Numerik eşitsizlik

9 != 7

True

<

Infix

Küçükse

9 < 7

False

>

Infix

Büyükse

9 > 7

True

<=

Infix

Küçük veya eşitse

7 <= 7

True

>=

Infix

Büyük veya eşitse

9 >= 7

True

eq

Infix

Karakter dizisi(String) eşitliği

"John" eq "John"

True

ne

Infix

String eşit değilse

"John" ne "Jane"

True

=

Infix

Atama

my $var = 7

7 değerini $var değişkenine atar

~

Infix

Stringleri birbirine bağlar

9 ~ 7

97

"Hi " ~ "there"

Hi there

x

Infix

String çoğaltır

13 x 3

131313

"Hello " x 3

Hello Hello Hello

~~

Infix

Akıllı eşleme

2 ~~ 2

True

2 ~~ Int

True

"Raku" ~~ "Raku"

True

"Raku" ~~ Str

True

"enlightenment" ~~ /light/

「light」

++

Önek(Prefix)

Arttırma

my $var = 2; ++$var;

Değeri 1 arttırır ve sonucu 3 olarak döner

Sonek(Postfix)

Arttırma

my $var = 2; $var++;

2 sonucunu döner ve değeri 1 arttırır

--

Prefix

Azaltma

my $var = 2; --$var;

Değeri 1 azaltır ve sonucu 1 olarak döner

Postfix

Azaltma

my $var = 2; $var--;

2 sonucunu döner ve değeri 1 azaltır

+

Prefix

İşlenen değeri numerik sonuca zorlar

+"3"

3

+True

1

+False

0

-

Prefix

İşlenen değeri negatif numerik sonuca zorlar

-"3"

-3

-True

-1

-False

0

?

Prefix

İşlenen değeri mantıksal(boolean) sonuca zorlar

?0

False

?9.8

True

?"Hello"

True

?""

False

my $var; ?$var;

False

my $var = 7; ?$var;

True

!

Prefix

İşlenen değeri mantıksal sonuca zorlar ve tersini alır

!4

False

..

Infix

Aralık oluşturucu

0..5

0’dan 5’e

..^

Infix

Aralık oluşturucu

0..^5

0’dan 4’e

^..

Infix

Aralık oluşturucu

0^..5

1’den 5’e

^..^

Infix

Aralık oluşturucu

0^..^5

1’den 4’de

^

Prefix

Aralık oluşturucu

^5

0..^5’e demektir, 0’dan 4’e

…​

Infix

Tembel liste oluşturucu

0…​9999

aralıktaki eleman çağırılınca döndürür

|

Prefix

Düzleştirme

|(0..5)

(0 1 2 3 4 5)

|(0^..^5)

(1 2 3 4)

2.2. Ters Operatörleri

Herhangi bir işlemden önce R kullanmak işlemi tersine çevirecektir.

Operasyon Sonuç Ters Operatörü Sonuç

2 / 3

0.666667

2 R/ 3

1.5

2 - 1

1

2 R- 1

-1

2.3. İndirgeme Operatörleri

Listelerle çalışırlar ve [] ile çevrelenirler.

Operasyon Sonuç İndirgeme Operatörü Sonuç

1 + 2 + 3 + 4 + 5

15

[+] 1,2,3,4,5

15

1 * 2 * 3 * 4 * 5

120

[*] 1,2,3,4,5

120

Operatörler hakkında daha fazla bilgiye https://docs.perl6.org/language/operators adresinden ulaşabilirsiniz.

3. Değişkenler

Raku’da değişkenler üç kategoriye ayrılır: Skalar değişkenler, Diziler ve Hashler.

Değişkenlerin başın da, değişkenleri kategorize etmek için kullanılan karakterler vardır.

  • $ skalar değişkenler için kullanılır.

  • @ diziler için kullanılır.

  • % hashler için kullanılır.

3.1. Skalar Değişkenler

Bir skalar değeri veya referansı tutar.

# String
my $name = 'Cahit Sıtkı Tarancı';
say $name;

# Integer
my $age = 35;
say $age;

Bir skaların tuttuğu değere göre bazı operasyonlar gerçekleştirebiliriz.

String
my $name = 'Cahit Sıtkı Tarancı';
say $name.uc;
say $name.chars;
say $name.flip;
CAHIT SITKI TARANCI
19
ıcnaraT ıktıS tihaC
String verilere uygulanabilen metotların listesi için https://docs.perl6.org/type/Str adresine bakabilirsiniz.
Integer
my $age = 17;
say $age.is-prime;
True
Integer verilere uygulanabilen metotların listesi için https://docs.perl6.org/type/Int adresine bakabilirsiniz.
Rational Number
my $age = 2.3;
say $age.numerator;
say $age.denominator;
say $age.nude;
23
10
(23 10)
Rational number verilere uygulanabilen metotların listesi için https://docs.perl6.org/type/Rat adresine bakabilirsiniz.

3.2. Diziler

Diziler birden fazla veri içerebilen listelerdir.

my @animals = 'camel','llama','owl';
say @animals;

Diziler ile yapılabilecek işlemler:

~ operatörü ile string birleştirme yapabiliyorduk.
Betik
my @animals = 'camel','vicuña','llama';
say "The zoo contains " ~ @animals.elems ~ " animals";
say "The animals are: " ~ @animals;
say "I will adopt an owl for the zoo";
@animals.push("owl");
say "Now my zoo has: " ~ @animals;
say "The first animal we adopted was the " ~ @animals[0];
@animals.pop;
say "Unfortunately the owl got away and we're left with: " ~ @animals;
say "We're closing the zoo and keeping one animal only";
say "We're going to let go: " ~ @animals.splice(1,2) ~ " and keep the " ~ @animals;
Çıktı
The zoo contains 3 animals
The animals are: camel vicuña llama
I will adopt an owl for the zoo
Now my zoo has: camel vicuña llama owl
The first animal we adopted was the camel
Unfortunately the owl got away and we're left with: camel vicuña llama
We're closing the zoo and keeping one animal only
We're going to let go: vicuña llama and keep the camel
Açıklama

.elems dizideki elemanların listesini döndürür. .push() diziye bir veya birden fazla eleman eklemek için kullanılır. .pop dizinin sonundaki elemanı diziden çıkarır ve çıkan elemanı döndürür. .splice(a,b) a, b pozisyonlarını dahil arada kalan elemanları diziden çıkaracaktır.

3.2.1. Sabit Boyutlu Diziler

Temel bir dizi tanımı aşağıdaki gibidir:

my @array;

Temel bir dizi sonsuz uzunlukta olabilir ve uzunluğu eleman ekledikçe otomatik arttırılır. Herhangi bir sayıda elemanı kabul eder. Buna karşılık sabit boyutlu diziler de oluşturulabilir. Bu diziler tanımlanan uzunluğun dışına çıkamaz.

Sabit boyutlu bir dizi tanımlamak için, adından hemen sonra köşeli parantez içerisinde tutabileceği eleman sayısı belirtilir.

my @array[3];

Bu dizi 0’dan 2’ye indexlenen en fazla 3 elemana sahip olabilecektir.

my @array[3];
@array[0] = "first value";
@array[1] = "second value";
@array[2] = "third value";

Bu diziye dördüncü bir eleman eklemeye çalıştığımızda:

my @array[3];
@array[0] = "first value";
@array[1] = "second value";
@array[2] = "third value";
@array[3] = "fourth value";
Index 3 for dimension 1 out of range (must be 0..2)

hatasını döndürecektir.

3.2.2. Çok Boyutlu Diziler

Şimdiye kadar görüğümüz diziler tek boyutluydu. Raku çok boyutlu diziler tanımlamamıza izin verir.

my @tbl[3;2];

Bu dizi iki boyutludur. İlk boyut maksimum 3 değer, ikinci boyut maksimum 2 değer içerebilir. 3x2’lik bir tablo gibi düşünülebilir.

my @tbl[3;2];
@tbl[0;0] = 1;
@tbl[0;1] = "x";
@tbl[1;0] = 2;
@tbl[1;1] = "y";
@tbl[2;0] = 3;
@tbl[2;1] = "z";
say @tbl
[[1 x] [2 y] [3 z]]
Dizinin görsel sunumu:
[1 x]
[2 y]
[3 z]
Diziler hakkında daha fazla bilgiye https://docs.perl6.org/type/Array adresinden ulaşabilirsiniz.

3.3. Hashler

Bir hash Anahtar/Değer çiftlerinden oluşur.
my %capitals = ('UK','London','Germany','Berlin');
say %capitals;
Hash oluşturmanın farklı bir yolu:
my %capitals = (UK => 'London', Germany => 'Berlin');
say %capitals;

Hashler üzerinde çalıştırılabilecek bazı metotlar şöyle:

Betik
my %capitals = (UK => 'London', Germany => 'Berlin');
%capitals.push: (France => 'Paris');
say %capitals.kv;
say %capitals.keys;
say %capitals.values;
say "The capital of France is: " ~ %capitals<France>;
Çıktı
(France Paris Germany Berlin UK London)
(France Germany UK)
(Paris Berlin London)
The capital of France is: Paris
Açıklama

.push: (anahtar => 'Değer') yeni bir anahtar değer çifti ekler.
.kv tüm anahtar ve değerlerin bir listesini döndürür.
.keys tüm anahtarların listesini döndürür.
.values tüm değerlerin listesini döndürür.
%hash<anahtar> ile özel bir değere ulaşılabilir.

Hashler hakkında daha fazla bilgiye https://docs.perl6.org/type/Hash adresinden ulaşabilirsiniz.

3.4. Veri Tipleri

Önceki bölümlerde değişkenlerin ne tür değerler tutması gerektiğini belirtmedik.

.WHAT değişkende tutulan değerin tipini döndürür.
my $var = 'Text';
say $var;
say $var.WHAT;

$var = 123;
say $var;
say $var.WHAT;

Yukarıdaki örnekte görülebileceği gibi $var değişkeninin tipi (Str) ve ardından (Int) oldu.

Bu programlama tarzına dinamik yazım denir. Dinamik değişkenlerin herhangi bir değer içerebileceği anlamındadır.

Şimdi aşağıdaki örneği çalıştırmayı deneyelim, değişken adından önce Int olduğunu tanımlayalım.

my Int $var = 'Text';
say $var;
say $var.WHAT;

Bu kod çalışmaz ve bir hata mesajı döndürür: Type check failed in assignment to $var; expected Int but got Str

Değişkenin tipinin (Int) olması gerektiğini söyledik ve bir (Str) atamaya çalıştığımızda başarısız oldu, hata ile karşılaştık.

Bu programlama tarzına statik yazım denir. Değişkenin tipinin atama öncesi tanımlandığı ve değiştirilemeyeceği anlamına gelir.

Raku kadelemeli -gradually typed olarak yazılan bir dil olarak tanımlanmıştır; hem statik hem de dinamik yazıma izin verir.

Diziler ve hashler statik olarak yazılabilir:
my Int @array = 1,2,3;
say @array;
say @array.WHAT;

my Str @multilingual = "Hello","Salut","Hallo","您好","안녕하세요","こんにちは";
say @multilingual;
say @multilingual.WHAT;

my Str %capitals = (UK => 'London', Germany => 'Berlin');
say %capitals;
say %capitals.WHAT;

my Int %country-codes = (UK => 44, Germany => 49);
say %country-codes;
say %country-codes.WHAT;
Table 1. Sık kullanılan tiplerin listesi:

Tip

Açıklama

Örnek

Sonuç

Mu

Raku tür hiyerarşisinin kökü

Any

Yeni sınıflar ve çoğu tanımlı sınıf için varsayılan taban sınıf

Cool

Stringler veya sayılar gibi birbiri yerine kullanılabilen değerler

my Cool $var = 31; say $var.flip; say $var * 2;

13 62

Str

Karakter dizileri

my Str $var = "NEON"; say $var.flip;

NOEN

Int

Tam sayılar (Keyfi hassasiyet)

7 + 7

14

Rat

Rasyonel sayılar (Sınırlı hassasiyet)

0.1 + 0.2

0.3

Bool

Mantıksal

!True

False

3.5. İçgözlem

Veri tipi gibi nesne özellikleri hakkında bilgi alma sürecidir.
Önceki örneklerde değişken tipini döndürmek için .WHAT kullanmıştık.

my Int $var;
say $var.WHAT;    # (Int)
my $var2;
say $var2.WHAT;   # (Any)
$var2 = 1;
say $var2.WHAT;   # (Int)
$var2 = "Hello";
say $var2.WHAT;   # (Str)
$var2 = True;
say $var2.WHAT;   # (Bool)
$var2 = Nil;
say $var2.WHAT;   # (Any)

Tipi tanımlanan boş bir değişkenin tipi, tanımlanan tip olur.
Tipi tanımlanmayan boş bir değişkenin tipi (Any) olur.
Bir değişkenin tipini temizlemek için Nil ataması yapılır.

3.6. Kapsam (Scoping)

Kullanılmadan önce bir değişkenin tanımlanması gerekir. Raku’da birçok tanımlama kullanılmaktadır. Biz şuana kadar my kullanıyorduk.

my $var=1;

my bildirimi kapsamı verir. Başka bir deyişle my ile tanımlanan bir değişken yalnızca tanımladığı blokta erişilebilir olacaktır.

Raku’da bir blok { } ile sınırlandırılmış alandır. Eğer yazdığımız kodda blok blunmuyorsa, değişken Raku betiğinin tamamında kullanılabilir olacaktır.

{
  my Str $var = 'Text';
  say $var;   # Erişilebilir
}
say $var;   # Erişilemez ve hata döndürür

Bir değişkene yalnızca tanımlandığı blokta erişilebildiğinden, aynı değişken adı farklı bir blokta kullanılabilir.

source,perl6]

{
  my Str $var = 'Text';
  say $var;
}
my Int $var = 123;
say $var;

3.7. Atama ve Bağlama (Assignment vs. Binding)

Önceki örneklerde, değişkenlere değer atamanın nasıl yapıldığını gördük. Atama = operatörü ile yapılır.

my Int $var = 123;
say $var;

Bir değişkene atanan değeri değiştirebiliriz:

Atama
my Int $var = 123;
say $var;
$var = 999;
say $var;
Çıktı
123
999

Öte yandan bir değişkene bağlanan veriyi değiştiremeyiz. Bağlama := operatörü ile yapılır.

Bağlama
my Int $var := 123;
say $var;
$var = 999;
say $var;
Çıktı
123
Cannot assign to an immutable value
Değişkenler diğer değişkenlere de bağlanabilir:
my $a;
my $b;
$b := $a;
$a = 7;
say $b;
$b = 8;
say $a;
Çıktı
7
8

Değişkenleri bağlama iki yönlüdür
$a := $b ve $b := $a aynı etkiye sahiptir.

Değişkenler ile ilgili daha fazla bilgiye https://docs.perl6.org/language/variables adresinden ulaşabilirsiniz.

4. Fonksiyonlar ve Mutatörler(Mutators)

Fonksiyonlar ile mutatörler arasında ayrım yapmak önemlidir. Fonksiyonlar çağırıldıkları nesnenin durumunu değiştirmezler. Mutatörler nesnenin durumunu değiştirirler ve metotlar gibi düşünülebilir.

Betik
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
my @numbers = [7,2,4,9,11,3];

@numbers.push(99);
say @numbers;      #1

say @numbers.sort; #2
say @numbers;      #3

@numbers.=sort;
say @numbers;      #4
Çıktı
[7 2 4 9 11 3 99] #1
(2 3 4 7 9 11 99) #2
[7 2 4 9 11 3 99] #3
[2 3 4 7 9 11 99] #4
Açıklama

.push bir mutatördür ve dizinin içeriğini değiştirir (#1)

.sort bir fonksiyondur ve dizinin sıralanmış halini döndürür. Ancak dizinin ilk halini değiştirmez.

  • (#2) Sıralanmış diziyi döndürür.

  • (#3) Dizinin ilk halinin hala değişmediğini gösterir.

Bir fonksiyonun mutatör görevi görmesi için .= kullanın. (#4) (Betiğimizin 9. satırında)

5. Döngüler ve Koşullar

Raku birçok döngü ve koşul yapısına sahiptir.

5.1. if

Kod ancak bir koşul sağlandığında çalışır. Yani bir ifadenin True olarak değerlendirilmesi gerekir.

my $age = 19;

if $age > 18 {
  say 'Welcome'
}

Koşul olumsuz False olarak değerlendirildiğinde yürütülecek alternatif blokları şu ifadeleri kullanarak belirleyebiliriz:

  • else

  • elsif

# değişkenin farklı değerleri için aynı kodu çalıştırın
my $number-of-seats = 9;

if $number-of-seats <= 5 {
  say 'I am a sedan'
} elsif $number-of-seats <= 7 {
  say 'I am 7 seater'
} else {
  say 'I am a van'
}

5.2. unless

if ifadesinin, olumsuz halini yazarken kullanılabilir.

örnek:

my $clean-shoes = False;

if not $clean-shoes {
  say 'Clean your shoes'
}

Yukarıdaki kod aşağıdaki şekilde yazılabilir:

my $clean-shoes = False;

unless $clean-shoes {
  say 'Clean your shoes'
}

Raku’da bir ifadeyi olumsuzlamak için ! veya not kullanılır.

unless (koşul) yerine if not (koşul) kullanılabilir.

unless kullanıldığı durumlarda else bloğu kullanılamaz.

5.3. with

if ifadesi gibi kullanılır ancak değişkenin tanımlanıp tanımlanmadığını kontrol eder.

my Int $var=1;

with $var {
  say 'Hello'
}

Kodu değişkene değer atamadan kullandığınızda birşey olmamalı.

my Int $var;

with $var {
  say 'Hello'
}

without ise with ifadesinin olumsuz versiyonudur. Bunu unless ifadesine benzetebilirsiniz.

Koşullu olan ilk with gerçekleşemez ise orwith kullanılarak alternatif blok belirlenebilir. with ve orwith ile if ve elsif benzetilebilir.

5.4. for

for döngüsü birden fazla değeri tek tek ele alır. Yineleme yapar.

my @array = [1,2,3];

for @array -> $array-item {
  say $array-item * 100
}

Bir yineleme değişkeni $array-item oluşturduğumuza ve her bir dizi elemanı için *100 işlemini gerçekleştirdiğimize dikkat edin.

5.5. given

Diğer dillerdeki switch ifadesinin Raku’daki daha güçlü ifadesidir.

my $var = 42;

given $var {
    when 0..50 { say 'Less than or equal to 50'}
    when Int { say "is an Int" }
    when 42  { say 42 }
    default  { say "huh?" }
}

Başarılı bir eşleme sonrasında eşleme işlemi durdurulur ve given sonlanır.

Alternatif olarak proceed ifadesi ile Perl 6’ya başarılı bir eşleme sonrasında bile eşlemeye devam etmesi söylenebilir.

my $var = 42;

given $var {
    when 0..50 { say 'Less than or equal to 50';proceed}
    when Int { say "is an Int";proceed}
    when 42  { say 42 }
    default  { say "huh?" }
}

5.6. loop

loop for döngüsü yazmanın farklı bir yoludur.

Aslında loop C programlama dili ailesinde for döngüsü yazmaya benzer.

Raku, C ailesi dillerindendir.

loop (my $i = 0; $i < 5; $i++) {
  say "The current number is $i"
}
Döngüler ve koşullar hakkında daha fazla bilgiye https://docs.perl6.org/language/control adresinden ulaşabilirsiniz.

6. G/Ç (I/O)

Raku’da en yaygın Girdi/Çıktı arabirimlerinden ikisi Terminal ve Dosyadır.

6.1. Terminal Kullanarak Basit G/Ç

6.1.1. say

say standart çıktıya sonuna satır sonu karakteri ekleyerek yazar.

say 'Hello Mam.';
say 'Hello Sir.';

Betik iki farklı satır üzerine yazar.

6.1.2. print

print, say gibi kullanılır ancak satır sonu karakteri eklemez. Yani yeni bir satıra geçmez.

Yukarıdaki say ifadesini print ile değiştirin ve sonuçları karşılaştırın.

6.1.3. get

get terminal ekranından giriş almanızı sağlar.

my $name;

say "Hi, what's your name?";
$name = get;

say "Dear $name welcome to Raku";

Yukarıdaki kod çalıştırıldığında terminal adınızı girmenizi bekliyor olacak. Adnınızı girin ve ardından [Enter] tuşuna basın.

6.1.4. prompt

prompt, print ve get ifadesinin kombinasyonudur.

Yukarıdaki kod şu şekilde yazılabilir:

my $name = prompt "Hi, what's your name? ";

say "Dear $name welcome to Raku";

6.2. Kabuk Komutu Çalıştırmak

Kabuk komutlarını çalıştırmak için iki altyordam kullanılabilir:

  • run Kabuk içermeden harici bir komut çalıştırır.

  • shell Sistem kabuğu aracılığı ile bir komut çalıştırır. Platform ve kabuk bağımlıdır.

Eğer Linux/macOS kullanıyorsanız
my $name = 'Neo';
run 'echo', "hello $name";
shell "ls";
Eğer Windows kullanıyorsanız
shell "dir";

echo ve ls, Linux kabuğu için ortak anahtar kelimelerdir. echo metni terminale yazdırır. (Raku’da print’in eşdeğeri) ls mevcut izindeki tüm dosya ve klasörleri listeler.

dir ise ls’in Windows ortamındaki eş değeridir.

6.3. Dosya G/Ç

6.3.1. slurp

Dosyadan veri okunmasını sağlar.

İçeriği aşağıdaki gibi olan bir dosya yaratalım:

datafile.txt
John 9
Johnnie 7
Jane 8
Joanna 7
my $data = slurp "datafile.txt";
say $data;

6.3.2. spurt

Dosyaya veri yazılmasını sağlar.

my $newdata = "New scores:
Paul 10
Paulie 9
Paulo 11";

spurt "newdatafile.txt", $newdata;

Kod çalıştırıldıktan sonra newdatafile.txt isminde yeni bir dosya oluşturur ve içine $newdata değişkeninin içeriğini yazar.

6.4. Dosya ve Dizinler ile Çalışmak

Raku kabuk komutlarına başvurmadan(örneğin ls) bir dizinin içeriğini listeleyebilir.

say dir;                # Mevcut dizindeki dosya ve klasörleri listeler
say dir "/Documents";   # Özel bir dizindeki dosya ve klasörleri listeler

Buna ek olarak dizinleri oluşturabilir ve silebiliriz.

mkdir "newfolder";
rmdir "newfolder";

mkdir yeni bir dizin oluşturur.
rmdir boş dizini siler veya dizin boş değilse hata döndürür.

Yolun bir dizin veya bir dosya olup olmadığını kontrol edebilirsiniz.

Aşağıdaki betiği çalıştırdığınız dizinde folder123 adında boş bir klasör ve script123.pl6 adında boş bir pl6 dosyası oluşturun.

say "script123.pl6".IO.e;
say "folder123".IO.e;

say "script123.pl6".IO.d;
say "folder123".IO.d;

say "script123.pl6".IO.f;
say "folder123".IO.f;

IO.e dizinin/dosyanın mevcut olup olmadığını kontrol eder.
IO.f yolun dosya olup olmadığını kontrol eder.
IO.d yolun dizin olup olmadığını kontrol eder.

Windows kullanıcıları dizinleri tanımlamak için / veya \\ kullanmalı
C:\\rakudo\\bin
C:/rakudo/bin
G/Ç hakkında daha fazla bilgiye https://docs.perl6.org/type/IO adresinden ulaşabilirsiniz.

7. Altyordamlar

7.1. Tanımlama

Altyordamlar (altprogramlar veya fonksiyonlar olarak da adlandırılır), işlevselliği paketleme ve yeniden kullanma yöntemidir.

Altprogram tanımlaması sub anahtarıyla başlar. Tanımlandıktan sonra adı ile çağırılabilir. Aşağıdaki örneği inceleyin:

sub alien-greeting {
  say "Hello earthlings";
}

alien-greeting;

Yukarıdaki örnek herhangi bir girdi gerektirmeyen altyordam idi.

7.2. İmza

Altprogramlar parametre alabilir. Bir altyordam sıfır veya daha fazla parametre alabilir. Bir altyordamın tanımladığı parametre türü ve sayısına imzası denir.

Aşağıdaki altprogram bir string değişkeni parametre olarak kabul eder.

sub say-hello (Str $name) {
    say "Hello " ~ $name ~ "!!!!"
}
say-hello "Paul";
say-hello "Paula";

7.3. Çoklu Altyordam(Multiple dispatch)

Aynı adı taşıyan ancak imzaları farklı olan birden fazla altprogram tanımlamak mümkündür. Altprogram çağrıldığında, çalışma zamanı ortamı, verilen bağımsız değişkenlerin sayısı ve türüne göre hangi sürümü kullanacağına karar verecektir. Bu tür bir altprogram sub yerine multi anahtar sözcüğü kullanılması dışında altyordamlar ile aynı şekilde tanımlanır.

multi greet($name) {
    say "Good morning $name";
}
multi greet($name, $title) {
    say "Good morning $title $name";
}

greet "Johnnie";
greet "Laura","Mrs.";

7.4. Varsayılan ve İsteğe Bağlı Parametreler

Altyordam, parametre alacak şekilde tanımlandıysa ve gerekli parametre verilmeden çalıştırılırsa hata döner.

Raku bize opsiyonel ve varsayılan parametreli olmak üzere iki altyordam tanımlama imkanı verir.

Opsiyonel parametreleri belirtmek için sonuna ? karakteri koyulur.

sub say-hello($name?) {
  with $name { say "Hello " ~ $name }
  else { say "Hello Human" }
}
say-hello;
say-hello("Laura");

Kullanıcı isteğe bağlı parametreyi sağlamazsa parametre için varsayılan değer kullanılabilir. Bu altyordam tanımında belirtilen parametreye değer atayarak yapılır.

sub say-hello($name="Matt") {
  say "Hello " ~ $name;
}
say-hello;
say-hello("Laura");

7.5. Dönüş Değeri

Şmdiye kadar gördüğümüz altprogramlar bir şeyler yapıyordu, örneğin terminalde bazı metinler gösteriyordu.

Bazen dönüş değeri için bir altprogram yürütürüz, böylece daha sonra program akışında bunu kullanabiliriz.

Belirtilmemiş dönüş
sub squared ($x) {
  $x ** 2;
}
say "7 squared is equal to " ~ squared(7);

Netlik açısından dönüşü açıkça belirtmek iyi bir fikirdir. Bunun için return anahtar kelimesi kullanılır.

Belirtilmiş dönüş
sub squared ($x) {
  return $x ** 2;
}
say "7 squared is equal to " ~ squared(7);

7.5.1. Dönüş Değerini Sınırlama

Önceki örneklerde parametrenin belirli bir türde olmasını nasıl sınırlayabileceğimizi gördük. Aynı şey dönüş değeri için de yapılabilir. Dönüş değerini belirli bir tür ile sınırlamak için imza içinde returns veya --> işareti kullanabiliriz.

returns kullanarak
sub squared ($x) returns Int {
  return $x ** 2;
}
say "1.2 squared is equal to " ~ squared(1.2);
Ok kullanarak
sub squared ($x --> Int) {
  return $x ** 2;
}
say "1.2 squared is equal to " ~ squared(1.2);

Tip sınırlamasına uyan bir dönüş değeri sağlanmadığı takdirde hata fırlatılır.


Peki beklenen değer Int ama Rat(1.44) değeri varsa. ---

Tip kısıtlamaları dönüş değerinin türünü denetlemekle kalmaz, tanımlanışınıda kontrol edebilir. Önceki örneklerde dönüş değerinin Int olması gerektiğini belirttik. Aşağıda önceki örneğin değiştirilmiş bir hali verilmiştir, :D ifadesi döndürülen Int’in tanımlanmasını zorlamak için kullanılır.

sub squared ($x --> Int:D) {
  return $x ** 2;
}
say "1.2 squared is equal to " ~ squared(1.2);
Altyordamlar ve fonksiyonlar ile ilgili daha fazla bilgiye https://docs.perl6.org/language/functions adresinden ulaşabilirsiniz.

8. Fonksiyonel Programlama

Bu bölümde fonksiyonel programlamayı kolaylaştıran özelliklere bakacağız.

8.1. Fonksiyonlar Birinci Sınıf Vatandaşlardır

Fonksiyonlar/Altyordamlar birinci sınıf vatandaşlardır:

  • Argüman olarak iletilebilirler

  • Farklı fonksiyonları döndürebilirler

  • Değişkenlere atanabilirler

Harika bir örnek map fonksiyonudur. map yüksek seviyeli bir fonksiyondur, başka bir fonksiyonu argüman olarak kabul edebilir.

Betik
my @array = <1 2 3 4 5>;
sub squared($x) {
  $x ** 2
}
say map(&squared,@array);
Çıktı
(1 4 9 16 25)
Açıklama

Bir parametre alan ve paremetreyi kendisi ile çarpan sonucu döndüren bir altyordam tanımladık. Daha sonra, yüksek seviye bir fonksiyon olan map kullandık ve iki parametre verdik, karesi altyordamı ve bir dizi. Sonuç dizinin karesi alınmış öğelerinin bir listesidir.

Bir altyordamı parametre olarak alırken adının başına & karakterini eklememiz gerekir.

8.2. Anonim Fonksiyonlar

Anonim fonksiyonlara lambda denir.
Anonim fonksiyonların tanımlayıcısı(adı) yoktur.

map örneğini anonim fonksiyon kullanarak tekrar yazalım.

my @array = <1 2 3 4 5>;
say map(-> $x {$x ** 2},@array);

Altyordamı bildirmek ve map fonksiyonuna parametre olarak vermek yerine, anonim fonksiyon olarak tanımladık -> $x {$x ** 2}.

Raku dilinde bu gösterimi sivri blok olarak adlandırıyoruz.

Değişkenlere fonksiyon atamak için de sivri blok kullanılabilir:

my $squared = -> $x {
  $x ** 2
}
say $squared(9);

8.3. Zincirleme

Raku’da fonksiyonlar zincirlenebilir, bu sayede bir fonksiyonun sonucunu argüman olarak başka birine geçmeniz gerekmez.

Örnek vermek gerekirse: Bir dizi verildiğinde, dizinin büyükten küçüğe sıralı ve benzersiz değerlerini döndürmeniz gerekebilir.

Zincirsiz çözüm:

my @array = <7 8 9 0 1 2 4 3 5 6 7 8 9>;
my @final-array = reverse(sort(unique(@array)));
say @final-array;

Buna karşı zincirleme yöntemde aynı örnek şu şekilde yazılabilir:

my @array = <7 8 9 0 1 2 4 3 5 6 7 8 9>;
my @final-array = @array.unique.sort.reverse;
say @final-array;

Zincirleme yönteminin anlaşılması daha kolay olduğunu görebilirsiniz.

8.4. Besleme Operatörü(Feed Operator)

Bazı fonksiyonel programlama dillerinde boru(pipe) olarak adlandırılan besleme operatörü, zincirleme işlemini daha da görselleştirir.

İleriye doğru besleme
my @array = <7 8 9 0 1 2 4 3 5 6 7 8 9>;
@array ==> unique()
       ==> sort()
       ==> reverse()
       ==> my @final-array;
say @final-array;

@array ile başlanır ardından benzersiz öğelerin listesi döndürülür sıralanır ters çevrilir @final-array adlı değişkende depolanır. --- İlk adımdan son adıma kadar işlem akışı yukarıdan aşşağıya iner.

Geriye doğru besleme
my @array = <7 8 9 0 1 2 4 3 5 6 7 8 9>;
my @final-array-v2 <== reverse()
                   <== sort()
                   <== unique()
                   <== @array;
say @final-array-v2;
Açıklama

Geriye doğru besleme ileriye doğru beslemeye benzer ancak tam tersidir. Akış son adımdan ilk adıma kadar aşağıdan yukarıya doğrudur.

8.5. Hiper Operatörü(Hyper operator)

>> ile temsil edilir. Listenin tüm elemanları üzerinde fonksiyon çağıracağından sonuçların bir listesini döndürür.

my @array = <0 1 2 3 4 5 6 7 8 9 10>;
sub is-even($var) { $var %% 2 };

say @array>>.is-prime;
say @array>>.&is-even;

Hiper operatörü ile dizinin her bir elemanı için tek olma veya çift olma durumunu kontrol ettik. Bu her bir değeri yenilemek için for döngüsü yazmamıza gerek kalmadığı için pratiktir.

8.6. Kavşaklar (-Junctions)

Bir kavşak, değerlerin mantıksal bir süperpozisyonudur.

Aşağıdaki örnekte 1|2|3 kavşaktır.

my $var = 2;
if $var == 1|2|3 {
  say "The variable is 1 or 2 or 3"
}

Kavşak kullanımı genellikle autothreading'i tetikler. Bir kavşak noktası için işlem yapılır ve tüm sonuçlar yeni bir kavşağa birleştirilir.

8.7. Tembel Listeler

Tembel liste, tembel olarak değerlendirilen bir listedir.
Tembel değerlendirme, bir işlemin değerlendirilmesini gerekli olana kadar geciktirir ve sonuçların bir arama tablosunda depolayarak değerlendirmenin tekrarını önler.

Yararları:

  • Gereksiz hesaplamalardan kaçınarak performans artışı.

  • Teorik olarak sonsuz veri yapıları oluşturma.

  • Kontrol akışını tanımlama becerisi.

Tembel liste oluşturmak için operatörü kullanılır. Tembel liste başlangıç elemanları, arttırım ve son nokta içerir.

Basit bir tembel liste
my $lazylist = (1 ... 10);
say $lazylist;

Başlangıç noktası 1 ve bitiş noktası 10’dur. Arttırım tanımlanmadığı için varsayılan olarak +1 artar. Diğer bir deyişle, bu tembel liste talep edilirse (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) elamanları döndürebilir.

Sonsuz tembel liste
my $lazylist = (1 ... Inf);
say $lazylist;

Bu liste 1’den sonsuza kadar olan herhangi bir tam sayıyı istendiği takdirde döndürebilir.

Artış değeri çıkarsanmış tembel liste
my $lazylist = (0,2 ... 10);
say $lazylist;

Bu tembel liste istediği takdirde (0, 2, 4, 6, 8, 10) elamaları döndürebilir.

Artış değeri belirlenmiş tembel liste
my $lazylist = (0, { $_ + 3 } ... 12);
say $lazylist;

Bu örnekte açıkça { } ile çevrelenmiş artış değeri tanımladık. Bu tembel liste istendiği takdirde (0, 3, 6, 9, 12) elemanlarını gösterir.

Son nokta artış değerinin geri dönebileceği değerlerden biri olmalıdır. Yukarıdaki örneği bitiş noktası 12 yerine 10 yazarsak durmaz. Artış değeri bitiş değerinin üzerinden zıplayacaktır. Alternatif olarak 0 … 10 yerine 0 …^* > 10 yazılabilir.

Durmaz
my $lazylist = (0, { $_ + 3 } ... 10);
say $lazylist;
Durur
my $lazylist = (0, { $_ + 3 } ...^ * > 10);
say $lazylist;

8.8. Closures

Closures bir fonksiyonun içinde verilen değere göre döndürülen başka fonksiyonlardır.

sub generate-greeting {
    my $name = "John Doe";
    sub greeting {
      say "Good Morning $name";
    };
    return &greeting;
}
my $generated = generate-greeting;
$generated();

Yukarıdaki kodu çalıştırdığımızda terminal ekranında Good Morning John Doe çıktısını görürüz.
Sonuç oldukça basit olmakla birlikte, ilginç olan greeting altyordamının generate-greeting tarafından döndürülmüş olmasıdır.

$generated bir closure haline geldi.

closure iki şeyi birleştiren bir nesne türüdür:

  • Bir Altyordam

  • Altprogramın oluşturulduğu ortam

Ortam, closure’un oluşturduğu kapsamdaki herhangi bir yerel değişkenden oluşur. Bu durumda $generated, closure oluşturulduğunda var olan greeting altyordamını ve Jhon Doe dizisini birleştiren bir closure olur.

Şimdi daha ilginç bir örneği inceleyelim.

sub greeting-generator($period) {
  return sub ($name) {
    return "Good $period $name"
  }
}
my $morning = greeting-generator("Morning");
my $evening = greeting-generator("Evening");

say $morning("John");
say $evening("Jane");

Bu örnekte, greeting-generator($period) altyordamını tanımladık. Altyordamımız farklı bir altyordam döndürür. Döndürülen altprogram, tek parametre alır ve string döndürür.

greetin-generator bir altyordam fabrikasıdır. Örneğimizde greeting-generator kullanılarak iki yeni altyordam oluşturduk. Birisi Good Morning ve diğeri Good Evening diyor.

$morning ve $evening her ikiside closure olur. Altyordamlar farklı ortamlarda tutulurlar ancak aynı içeriği kullanırlar. $morning ortamında $period Morning’dir. `$evening ortamında $period `Evening’dir.

9. Sınıflar ve Nesneler

Bir önceki bölümde Raku’nun Fonksiyonel Programlamayı nasıl kolaylaştırdığını öğrendik.
Bu bölümde, Raku’daki Nesne Yönelinli Programlamaya göz atacağız.

9.1. Giriş

Nesne Yöneli programlama günümüzde yaygın olarak kullanılan paradigmalardan biridir.
Bir nesne birlikte paketlenmiş bir dizi değişken ve altyordamdır.
Değişkenlere attributes(özellikler) denir ve altprogramlara metot denir.
Özellikler nesnenin durumunu tanımlar, metotlar ise nesnenin davranışını tanımlar.

Bir class nesneler oluşturmak için şablondur.

İlişkiyi anlamak için aşağıdaki örneği ele alalım:

Bir odada 4 kişi var

objects ⇒ 4 kişi

Bu 4 kişi insan

class ⇒ İnsan

Farklı isimler, yaş, cinsiyet ve uyrukları var.

attributes ⇒ isim, yaş, cinsiyet, uyruk

Nesneye yönelik programlamada nesnelerin sınıfların örnekleri olduğunu söyleriz.

Aşağıdaki betiğe bakalım:

class Human {
  has $.name;
  has $.age;
  has $.sex;
  has $.nationality;
}

my $john = Human.new(name => 'John', age => 23, sex => 'M', nationality => 'American');
say $john;

class anahtar kelimesi sınıfı tanımlamak için kullanılır.
has anahtar kelimesi sınıfın niteliklerini tanımlamak için kullanılır. .new() metodu yapıcı(constructor)'ı çağırır. Nesneyi çağırıldığı sınıfın bir örneği olarak yaratır.

Betiğimizde, $john adında yeni bir "Human" örneği tanımladık Human.new().
.new() içinde belirtilen değişkenler temel alınan sınıfın niteliklerini belirtmek için kullanılır.

Bir sınıfa my kullanılarak kapsamı belirtilebilir:

my class Human {

}

9.2. Kapsülleme (Encapsulation)

Sınıf(class) özelliklerinin dışarıya kapalı olması ve bu sınıfın her türlü veri iletişiminin kontrol altındaki metotlar ile yapılmasıdır.

Aşağıdaki betikler aynı sonuca sahiptir.

Değişkene doğrudan erişim:
my $var = 7;
say $var;
Kapsülleme:
my $var = 7;
sub sayvar {
  $var;
}
say sayvar;

sayvar metodu erişimcidir. Değişkenin kendisine doğrudan erişmeden, değerine erişmemize izin verir.

Raku kapsülleme kullanımını kolaylaştırılmıştır:

  • ! özelliğinin doğrudan dışarıdan erişilemez olduğunu belirtir.

  • . özellik için otomatik olarak erişimci oluşturulur.

Varsayılan olarak tüm özellikler özel(private)dir. Ancak her zaman ! kullanılması iyi bir alışkanlıktır.

Yukarıdaki sınıfı şu şekilde yeniden yazabiliriz:

class Human {
  has $!name;
  has $!age;
  has $!sex;
  has $!nationality;
}

my $john = Human.new(name => 'John', age => 23, sex => 'M', nationality => 'American');
say $john;

Betiğe say $john.age; komutunu ekleyelim.
Çalıştırmaya çalıştığımızda hata döndürür: Method 'age' not found for invocant of class 'Human' çünkü $age özeldir ve yalnızca nesne içinde kullanılabilir.

Şimdi has $!age yerine has $.age yazalım ve say $john.age ile tekrar çağıralım.

9.3. Yapıcı Metot

Raku’da tüm sınıflar varsayılan olarak .new() constructor'ı vardır.
Yeni nesneler oluşturmak için kullanılabilir.
Varsayılan constructor yalnızca parametreler ile kullanılabilir.
Yukarıdaki örneğimizde, .new() verilen parametreler ile tanımlanmıştır bu parametreler değişkenler için konum göstermiştir:

  • name => 'John'

  • age => 23

Peki konum göstermeden kullanmak isteseydik? Bunun için yeni bir yapıcı metot şu şekilde tanımlanabilir.

class Human {
  has $.name;
  has $.age;
  has $.sex;
  has $.nationality;
  # varsayılanı geçersiz kılan yeni bir yapıcı
  method new ($name,$age,$sex,$nationality) {
    self.bless(:$name,:$age,:$sex,:$nationality);
  }
}

my $john = Human.new('John',23,'M','American');
say $john;

9.4. Metotlar

9.4.1. Giriş

Metotlar bir nesnenin altyordamları'dır.
Altyordamlar gibi, bir dizi işlevselliği paketleme aracıdır. Parametre alabilirler.

Metotlar method kelimesi ile tanımlanır.
Nesne nitelikleri üzerinde bir takım işlemler yapmak için metotlar kullanılır. Bu kapsülleme kavramının kullanımını zorlar. Nesne nitelikleri, yalnızca metotlar kullanılarak nesne içinde manipüle edilebilir.

Nesne niteliklerine dışarıdan yalnızca nesne metotları ile iletişime geçilebilir. Niteliklere doğrudan erişim yoktur.

class Human {
 has $.name;
 has $.age;
 has $.sex;
 has $.nationality;
 has $.eligible;
 method assess-eligibility {
     if self.age < 21 {
       $!eligible = 'No'
     } else {
       $!eligible = 'Yes'
     }
 }

}

my $john = Human.new(name => 'John', age => 23, sex => 'M', nationality => 'American');
$john.assess-eligibility;
say $john.eligible;

Metotlar bir sınıfa tanımlandıktan sonra çağırmak için nesne . metot şeklinde çağrılır.

Bir metodun tanımı çevresinde, başka bir metodu çağırmak için nesnenin kendisine referans vermemiz gerekiyorsa self kelimesini kullanırız.
Bir özelliğe başvuru yapmamız gerekiyorsa . ile tanımlanmış olsa bile ! kullanırız.

Yukarıdaki örnekte if self.age < 21 ve if $!age < 21 aynı etkiye sahiptir, teknik olarak farklı olsalarda:

  • self.age .age metodunu çağırır
    Alternatif olarak $.age olarak yazılabilir.

  • $!age değişkenin doğrudan çağrısıdır.

9.4.2. Özel(Private) Metotlar

Metotlar sınıf dışından çağırılabilir.

Özel metotlar ise yalnızca Sınıf içerisinden çağırılabilir.
Olası kullanım durumu, belirli bir işlem için başka bir metot çağıran bir metot olacaktır.

Özel metot tanımlanırken ! kullanılmalıdır.
Özel metotlar . yerine ! ile çağırılır.

method !iamprivate {
  # kodlar
}

method iampublic {
  self!iamprivate;
  # kodlar
}

9.5. Sınıf Özellikleri(Class attributes)

Sınıf Özellikleri nesnenin değil sınıfın kendisine ait özelliklerddir.
Oluşturma sırasında başlatılabilirler.
Sınıf Nitelikleri has yerine my kullanılarak tanımlanır.

class Human {
  has $.name;
  my $.counter = 0;
  method new($name) {
    Human.counter++;
    self.bless(:$name);
  }
}
my $a = Human.new('a');
my $b = Human.new('b');

say Human.counter;

9.6. Erişim Türü

Şimdiye kadar gördüğümüz tüm örneklernesnelerin özelliklerinden bilgi almak için erişimciler kullanıldı.

Bir niteliğin değerini değiştirmemiz gerekiryorsa ne olur?
Bunun için is rw anahtar kelimesini kullanarak özelliği read/write(okuma/yazma) olarak etiketlemeliyiz.

class Human {
  has $.name;
  has $.age is rw;
}
my $john = Human.new(name => 'John', age => 21);
say $john.age;

$john.age = 23;
say $john.age;

Varsayılan olarak tüm nitelikler read only(yalnız okuma) olarak bildirilir ancak bunu açık olarak readonly kullanarak yapabiliriz.

9.7. Miras Alma(Inheritance)

Miras, nesne yönelimli programlamının başka bir kabulüdür.

Sınıfları tanımlarken, bazı özelliklerin/metotların birçok sınıfa ait olduğunu farkedeceğiz.
Bu durumda kodu tekrar tekrar yazmak yerine miras kavramını kullanacağız.

İnsanlar ve Çalışanlar için birer sınıf tanımlamak istediğimizi düşünelim.
İnsanlar iki niteliğe sahip olsun: adı ve yaşı.
Çalışanlar ise dört niteliğe sahip olsun: adı, yaşı, şirketi ve maaşı.

Bu sınıflar şu şekilde tanımlanabilir:

class Human {
  has $.name;
  has $.age;
}

class Employee {
  has $.name;
  has $.age;
  has $.company;
  has $.salary;
}

Yukarıdaki kod teknik olarak doğru olmakla birlikte, kavramsal olarak zayıf olduğu kabul edilir.

Bunu yazmanın daha iyi bir yolu şöyledir:

class Human {
  has $.name;
  has $.age;
}

class Employee is Human {
  has $.company;
  has $.salary;
}

is anahtar kelimesi miras alındığını tanımlar.
Bu şu şekilde ifade edilir, Çalışanlar sınıfı İnsanlar sınıfının çocuğudur veya İnsanlar sınıfı Çalışanlar sınıfının ebeveynidir.

Tüm çocuk sınıflar, ebeveyn sınıfın niteliklerini ve metotlarını devralırlar. Dolayısı ile tekrar tanımlanmalarına gerek yoktur.

9.7.1. Metotların Ezilmesi(Overriding)

Sınıflar, tüm nitelikleri ve metotları ebeveyn sınıflarından devralır.
Çocuk sınıfındaki metodun devralınan metottan farklı davranması gereken durumlar olabilir.
Bunun üstesinden gelmek için, metodu çocuk sınıfta yeniden tanımlarız.
Bu kavrama Overriding(ezme, geçersiz kılma) denir.

Aşağıdaki örnekte, introduce-yourself yöntemi Çalışan sınıfı tarafından devralınır.

class Human {
  has $.name;
  has $.age;
  method introduce-yourself {
    say 'Hi I am a human being, my name is ' ~ self.name;
  }
}

class Employee is Human {
  has $.company;
  has $.salary;
}

my $john = Human.new(name =>'John', age => 23,);
my $jane = Employee.new(name =>'Jane', age => 25, company => 'Acme', salary => 4000);

$john.introduce-yourself;
$jane.introduce-yourself;

Ezme şöyle çalışır:

class Human {
  has $.name;
  has $.age;
  method introduce-yourself {
    say 'Hi I am a human being, my name is ' ~ self.name;
  }
}

class Employee is Human {
  has $.company;
  has $.salary;
  method introduce-yourself {
    say 'Hi I am a employee, my name is ' ~ self.name ~ ' and I work at: ' ~ self.company;
  }

}

my $john = Human.new(name =>'John',age => 23,);
my $jane = Employee.new(name =>'Jane',age => 25,company => 'Acme',salary => 4000);

$john.introduce-yourself;
$jane.introduce-yourself;

Nesnenin hangi sınıfa dahil olduğuna bakılarak doğru metot çağırılır.

9.7.2. Altmetotlar

Alt sınıflar tarafından devralınmayan bir metot türüdür.
Onlara yalnızca tanımlandığı sınıftan erişilebilir.
Tanımlamak için submethod anahtar kelimesi kullanılır.

9.8. Çoklu Miras

Raku’da çoklu kalıtıma izin verilir. Bir sınıf birden çok sınıftan miras alabilir.

class bar-chart {
  has Int @.bar-values;
  method plot {
    say @.bar-values;
  }
}

class line-chart {
  has Int @.line-values;
  method plot {
    say @.line-values;
  }
}

class combo-chart is bar-chart is line-chart {
}

my $actual-sales = bar-chart.new(bar-values => [10,9,11,8,7,10]);
my $forecast-sales = line-chart.new(line-values => [9,8,10,7,6,9]);

my $actual-vs-forecast = combo-chart.new(bar-values => [10,9,11,8,7,10],
                                         line-values => [9,8,10,7,6,9]);
say "Actual sales:";
$actual-sales.plot;
say "Forecast sales:";
$forecast-sales.plot;
say "Actual vs Forecast:";
$actual-vs-forecast.plot;
Çıktı
Actual sales:
[10 9 11 8 7 10]
Forecast sales:
[9 8 10 7 6 9]
Actual vs Forecast:
[10 9 11 8 7 10]
Açıklama

combo-chart sınıfı iki seriyi tutabilmelidir; bir tanesi çubuklara çizilen gerçek değerler için, bir diğeri bir satırda çizilen tahmin değeri için.
Bu yüzden onu line-chart ve bar-chart sınıflarının bir çocuğu olarak tanımladık.
combo-chart üzerinde plot metodunu çağırmanın gerekli sonucu vermediğini fark etmiş olmalısınız. Sadece bir seri çizildi.
Bu neden oldu?
combo-chart, line-chart ve bar-chart sınıflarından miras alır ve her ikisinde de plot adlı bir yöntem bulunur. Raku, miras alınan metotlardan birini çağırarak çakışmayı çözmeye çalışacaktır.

Düzeltme

Doğru davranışı sağlamak için combo-chart üzerinde plot yöntemini geçersiz kıldık.

class bar-chart {
  has Int @.bar-values;
  method plot {
    say @.bar-values;
  }
}

class line-chart {
  has Int @.line-values;
  method plot {
    say @.line-values;
  }
}

class combo-chart is bar-chart is line-chart {
  method plot {
    say @.bar-values;
    say @.line-values;
  }
}

my $actual-sales = bar-chart.new(bar-values => [10,9,11,8,7,10]);
my $forecast-sales = line-chart.new(line-values => [9,8,10,7,6,9]);

my $actual-vs-forecast = combo-chart.new(bar-values => [10,9,11,8,7,10],
                                         line-values => [9,8,10,7,6,9]);
say "Actual sales:";
$actual-sales.plot;
say "Forecast sales:";
$forecast-sales.plot;
say "Actual vs Forecast:";
$actual-vs-forecast.plot;
Çıktı
Actual sales:
[10 9 11 8 7 10]
Forecast sales:
[9 8 10 7 6 9]
Actual vs Forecast:
[10 9 11 8 7 10]
[9 8 10 7 6 9]

9.9. Roller(Roles)

Roller, özelliklerin ve metotların bir koleksiyonu oldukları için sınıflara benzerler.

Roller role anahtar sözcüğü ile tanımlanır. Bir rol uygulanmak istenen sınıf do anahtar kelimesini kullanır.

Rolleri kullanarak çoklu miras örneğini tekrar yazalım:
role bar-chart {
  has Int @.bar-values;
  method plot {
    say @.bar-values;
  }
}

role line-chart {
  has Int @.line-values;
  method plot {
    say @.line-values;
  }
}

class combo-chart does bar-chart does line-chart {
  method plot {
    say @.bar-values;
    say @.line-values;
  }
}

my $actual-sales = bar-chart.new(bar-values => [10,9,11,8,7,10]);
my $forecast-sales = line-chart.new(line-values => [9,8,10,7,6,9]);

my $actual-vs-forecast = combo-chart.new(bar-values => [10,9,11,8,7,10],
                                         line-values => [9,8,10,7,6,9]);
say "Actual sales:";
$actual-sales.plot;
say "Forecast sales:";
$forecast-sales.plot;
say "Actual vs Forecast:";
$actual-vs-forecast.plot;

Örneği çalıştırdığınızda sonuçların aynı olduğunu göreceksiniz. Şimdi kendimize şu soruyu soralım: Roller sınıflar gibi kullanılıyorsa, bunların kullanım amacı nedir?
Sorumuza cevap verebilmesi için birden fazla miras alması için kullandığımız ilk betiği değiştirelim, plot metodunu geçersiz kıldık.

role bar-chart {
  has Int @.bar-values;
  method plot {
    say @.bar-values;
  }
}

role line-chart {
  has Int @.line-values;
  method plot {
    say @.line-values;
  }
}

class combo-chart does bar-chart does line-chart {
}

my $actual-sales = bar-chart.new(bar-values => [10,9,11,8,7,10]);
my $forecast-sales = line-chart.new(line-values => [9,8,10,7,6,9]);

my $actual-vs-forecast = combo-chart.new(bar-values => [10,9,11,8,7,10],
                                         line-values => [9,8,10,7,6,9]);
say "Actual sales:";
$actual-sales.plot;
say "Forecast sales:";
$forecast-sales.plot;
say "Actual vs Forecast:";
$actual-vs-forecast.plot;
Çıktı
===SORRY!===
Method 'plot' must be resolved by class combo-chart because it exists in multiple roles (line-chart, bar-chart)
Açıklama

Eğer aynı sınıfa birden fazla rol uygulanırsa ve çakışma varsa, derleme zamanı hatası alınır.
Bu çoklu mirastan daha güvenli bir yaklaşımdır, çoklu miras bunu hata olarak görmüyordu.

Roller bir çakışma olduğunda sizi uyaracaktır.

9.10. İçgözlem

Nesnenin tipi, nitelikleri veya metotları hakkında bilgi alma sürecidir.

class Human {
  has Str $.name;
  has Int $.age;
  method introduce-yourself {
    say 'Hi I am a human being, my name is ' ~ self.name;
  }
}

class Employee is Human {
  has Str $.company;
  has Int $.salary;
  method introduce-yourself {
    say 'Hi I am a employee, my name is ' ~ self.name ~ ' and I work at: ' ~ self.company;
  }
}

my $john = Human.new(name =>'John',age => 23,);
my $jane = Employee.new(name =>'Jane',age => 25,company => 'Acme',salary => 4000);

say $john.WHAT;
say $jane.WHAT;
say $john.^attributes;
say $jane.^attributes;
say $john.^methods;
say $jane.^methods;
say $jane.^parents;
if $jane ~~ Human {say 'Jane is a Human'};

İçgözlem aşağıdakiler tarafından kolaylaştırılır:

  • .WHAT — nesnenin oluşturulduğu sınıfı döndürür.

  • .^attributes — nesnenin tüm niteliklerini döndürür.

  • .^methods — nesnede çağırılabilecek tüm metotları döndürür.

  • .^parents — nesnenin ebeveynlerini döndürür.

  • ~~ — akıllı eşleme operatörünü çağırır. Nesne karşılaştırıldığı sınıftan veya çocuklarından herhangi biriyle yaratıldıysa True olarak değerlendirilir.

Nesne yönelimli programlama hakkında daha fazla bilgiye ulaşmak için:

10. İstisna İşleme(Exception Handling)

10.1. İstisna Yakalama(Catching Exceptions)

İstisna, çalışma anında gerçekleşen beklenmedik durumlardır. İstisna yakalama ise beklenmedik bir olayı algılayıp buna karşı bir kod parçasının çalıştırılmasıdır.

Doğru çalışan aşağıdaki betik dosyasını göz önünde bulundurursak:

my Str $name;
$name = "Joanna";
say "Hello " ~ $name;
say "How are you doing today?"
Çıktı
Hello Joanna
How are you doing today?

Şimdi bir istisna fırlatan aşağıdaki betik dosyasını göz önünde bulunduralım:

my Str $name;
$name = 123;
say "Hello " ~ $name;
say "How are you doing today?"
Çıktı
Type check failed in assignment to $name; expected Str but got Int
   in block <unit> at exceptions.pl6:2

Bir hata oluştuğunda (bu durumda string değişkenine tam sayı atamak) programın duracağına ve diğer kod satırlarının değerlendirilmeyeceğine dikkat edin.

İstisna işleme, betik dosyasının çalışmaya devam etmesi için atılan bir istisnayı yakalama işlemidir.

my Str $name;
try {
  $name = 123;
  say "Hello " ~ $name;
  CATCH {
    default {
      say "Can you tell us your name again, we couldn't find it in the register.";
    }
  }
}
say "How are you doing today?";
Çıktı
Can you tell us your name again, we couldn't find it in the register.
How are you doing today?

İstisna yakalama try-catch bloğu kullanılarak yapılır.

try {
  # kodlar
  # bir şeyler ters giderse catch bloğu çağırılır
  # ters giden bir şey olmazsa catch bloğu yok sayılır
  CATCH {
    default {
      # burada bulunan kod yalnızca istisna fırlatıldığında işleyecektir
    }
  }
}

CATCH bloğu given bloğu tanımlandığı gibi tanımlanabilir. Bu birçok istisna türünü farklı şekillerde ele alıp tutabiliriz demektir.

try {
  # kodlar
  # bir şeyler ters giderse catch bloğu çağırılır
  # ters giden bir şey olmazsa catch bloğu yok sayılır
  CATCH {
    when X::AdHoc   { # eğer hata tipi X::AdHoc ise çalışır }
    when X::IO      { # eğer hata tipi X::IO ise çalışır }
    when X::OS      { # eğer hata tipi X::OS ise çalışır }
    default         { # eğer istisna atılır ve yukarıdaki tiplere ait değilse buraya düşer }
  }
}

10.2. İstisna Fırlatma(Throwing Exceptions)

Raku da açıkça istisnaları atmanızı sağlar. İstisna fırlatmanın iki türü vardır:

  • ad-hoc(Özel) istisnalar

  • typed(Yazılan) İstisnalar

ad-hoc
my Int $age = 21;
die "Error !";
typed
my Int $age = 21;
X::AdHoc.new(payload => 'Error !').throw;

Özel istisnalar, die altyordamı ve ardından özel mesaj ile atılır.

Yazılan istisnalar nesnelerdir, bu yüzden yukarıdaki örnekte .new() yapıcısı kullanılmıştır. Yazılan tüm istisnalar X sınıfından alınır, birkaç örnek:
X::AdHoc en basit istisna tipidir
X::IO G/Ç hataları ile ilgilidir
X::OS OS hataları ile ilgilidir
X::Str::Numeric string ifadeyi sayıya zorlamakla ilgilidir.

İstisnalar ile ilgili daha fazla bilgiye https://docs.perl6.org/type-exceptions.html adresinden ulaşabilirsiniz.

11. Düzenli İfadeler (Regular Expression)

Düzenli ifadeler veya regex, desen eşleştirmesi için kullanılan bir dizi karakterdir. Bir desen olarak düşünün.

if 'enlightenment' ~~ m/ light / {
    say "enlightenment contains the word light";
}

Bu örnekte, akıllı eşleme operatörü ~~ bir stringin kelimeyi içerip içermediğini kontrol için kullanılır.

11.1. Regex Tanımlama

Şöyle tanımlanabilir:

  • /light/

  • m/light/

  • rx/light/

Açıkça belirtilmediği sürece boşluklar göz ardı edilir; m/light/ ve m/ light / aynı anlama gelir.

11.2. Karakter Eşleme

Alfanumerik karakterler ve altçizgi _ olduğu gibi yazılı. Diğer tüm karakterler ters eğik çizgi kullanılarak veya tırnak işareti ile çevrilmelidir.

Ters Eğik Çizgi
if 'Temperature: 13' ~~ m/ \: / {
    say "The string provided contains a colon :";
}
Tek Tırnak
if 'Age = 13' ~~ m/ '=' / {
    say "The string provided contains an equal character = ";
}
Çift Tırnak
if '[email protected]' ~~ m/ "@" / {
    say "This is a valid email address because it contains an @ character";
}

11.3. Kategorilerine Göre Karakter Eşleme

Karakterler, kategorilere ve zıt eşlemelerine göre sınıflandırılabilir. Bir kategori veya tersi ile karşılaşabiliriz.

Kategori

Regex

Ters

Regex

Kelime karakteri (harf, rakam veya altçizgi)

\w

Bir kelime karakteri haricindeki herhangi bir karakter

\W

Ondalıklı sayılar

\d

sayı harici herhangi bir karakter

\D

Boşluk

\s

boşluk haricinde herhangi bir karakter

\S

Yatay boşluk

\h

yatay boşluk harici herhangi bir karakter

\H

Dikey boşluk

\v

dikey boşluk harici herhangi bir karakter

\V

Tab

\t

Tab harici herhangi bir karakter

\T

Yeni satır

\n

Yeni satır karakteri hariç herhangi bir karakter

\N

if "John123" ~~ / \d / {
  say "This is not a valid name, numbers are not allowed";
} else {
  say "This is a valid name"
}
if "John-Doe" ~~ / \s / {
  say "This string contains whitespace";
} else {
  say "This string doesn't contain whitespace"
}

11.4. Unicode Özellikleri

Bir önceki bölümde görüldüğü gibi karakter kategorilerine karşı ters eşleme de yapılabilir.
Sistematik bir yaklaşım Unicode özeliklerini kullanmak olacaktır.
Bu yöntem ASCII standardı içindeki ve dışındaki karakter kategorileri ile eşleyebilmemizi sağlar. Unicode özellikleri <: > ile belirtilir.

if "Devanagari Numbers १२३" ~~ / <:N> / {
  say "Contains a number";
} else {
  say "Doesn't contain a number"
}
if "Привет, Иван." ~~ / <:Lu> / {
  say "Contains an uppercase letter";
} else {
  say "Doesn't contain an upper case letter"
}
if "John-Doe" ~~ / <:Pd> / {
  say "Contains a dash";
} else {
  say "Doesn't contain a dash"
}

11.5. Joker Karakterler

Joker karakterler regex ifadeler ile kullanılabilir.

Örneğin nokta . herhangi bir tek karakter anlamına gelir.

if 'abc' ~~ m/ a.c / {
    say "Match";
}
if 'a2c' ~~ m/ a.c / {
    say "Match";
}
if 'ac' ~~ m/ a.c / {
    say "Match";
} else {
    say "No Match";
}

11.6. Niceleyiciler

Nicelik belirteçleri, bir karakterin peşinden gelir ve bunu kaç kere beklediğimizi belirtmek için kullanılır.

Örneğin soru işareti ?, sıfır veya bir kez demektir.

if 'ac' ~~ m/ a?c / {
    say "Match";
} else {
    say "No Match";
}
if 'c' ~~ m/ a?c / {
    say "Match";
} else {
    say "No Match";
}

Yıldız *, sıfır veya birden çok kez anlamına gelir.

if 'az' ~~ m/ a*z / {
    say "Match";
} else {
    say "No Match";
}
if 'aaz' ~~ m/ a*z / {
    say "Match";
} else {
    say "No Match";
}
if 'aaaaaaaaaaz' ~~ m/ a*z / {
    say "Match";
} else {
    say "No Match";
}
if 'z' ~~ m/ a*z / {
    say "Match";
} else {
    say "No Match";
}

Artı +, en az bir kez demektir.

if 'az' ~~ m/ a+z / {
    say "Match";
} else {
    say "No Match";
}
if 'aaz' ~~ m/ a+z / {
    say "Match";
} else {
    say "No Match";
}
if 'aaaaaaaaaaz' ~~ m/ a+z / {
    say "Match";
} else {
    say "No Match";
}
if 'z' ~~ m/ a+z / {
    say "Match";
} else {
    say "No Match";
}

11.7. Eşleme Sonuçları

Bir string eşleştirme işlemi her regex’e karşı başarılı ise, eşeleme sonucu $/ özel karakterinde saklanır.

Betik
if 'Rakudo is a Raku compiler' ~~ m/:s Raku/ {
    say "The match is: " ~ $/;
    say "The string before the match is: " ~ $/.prematch;
    say "The string after the match is: " ~ $/.postmatch;
    say "The matching string starts at position: " ~ $/.from;
    say "The matching string ends at position: " ~ $/.to;
}
Çıktı
The match is: Raku
The string before the match is: Rakudo is a
The string after the match is: compiler
The matching string starts at position: 12
The matching string ends at position: 18
Açıklama

$/ eşleme nesnesini döner. (regexle eşlenen string)
Aşağıdaki yöntemler eşleme nesnesi üzerinden çağırılabilir: .prematch eşleşmeden önceki dizi döndürülür. .postmatch eşleşmeden sonraki dizi döndürülür. .from eşleştirmenin başladığı pozisyon döndürülür. .to eşleşmenin bittiği pozisyon döndürülür.

Varsayılan olarak regex tanımındaki boşluklar yok sayılır.
Boşluk içeren bir regexle eşleştirme yapmak istersek bunu açıkça belirtmeliyiz.
:s regex içinde m/:s Raku/ boşlukları hesaba katmaya zorlar.
Alternatif olarak regex’i şöyle yazmış olabiliriz: m/ Perl\s6 / ve \s kullanmış olabiliriz. Bu boşlukları temsil eder.
Bir regex tek boşluk içeriyorsa \s kullanmak iyi bir seçenektir.

11.8. Örnek

Bir e-postanın geçerli olup olmadığını kontrol edelim.
Örneğimiz için geçerli bir e-posta adresinin şöyle olduğunu varsayalım:
first name [dot] last name [at] company [dot] (com/org/net)

Bu örnekte kullanılan e-posta doğrulaması pek doğru değildir.
Tek amacı Raku’da düzenli ifadelerin kullanımını göstermektir.
Ürününüzde olduğu gibi kullanmayın.
Betik
my $email = '[email protected]';
my $regex = / <:L>+\.<:L>+\@<:L+:N>+\.<:L>+ /;

if $email ~~ $regex {
  say $/ ~ " is a valid email";
} else {
  say "This is not a valid email";
}
Çıktı

[email protected] is a valid email

Açıklama

<:L> tek harfle eşleştir
<:L>+ bir veya daha fazla harf ile eşleştir
\. bir [nokta] karakteri ile eşleştir
\@ bir [at] karakteri ile eşleştir
<:L+:N> bir harfle veya bir sayıyla eşleştir
<:L+:N>+ bir veya daha fazla harf veya rakamla eşleştir

Regex aşağıdaki gibi parçalanabilir:

  • first name <:L>+

  • [dot] \.

  • last name <:L>+

  • [at] \@

  • company name <:L+:N>+

  • [dot] \.

  • com/org/net <:L>+

Alternatif olarak bir regex adlandırılmış regexlere bölünebilir.
my $email = '[email protected]';
my regex many-letters { <:L>+ };
my regex dot { \. };
my regex at { \@ };
my regex many-letters-numbers { <:L+:N>+ };

if $email ~~ / <many-letters> <dot> <many-letters> <at> <many-letters-numbers> <dot> <many-letters> / {
  say $/ ~ " is a valid email";
} else {
  say "This is not a valid email";
}

Adlandırılmış bir regex şöyle bir sözdizimini kullanılarak tanımlanır: my regex regex-name { regex definition }
Adlandırılmış bir regex şöyle bir sözdizimini kullanarak çağrılabilir: <regex-name>

Düzenli ifadeler hakkında daha fazla bilgi için https://docs.perl6.org/language/regexes adresini ziyaret edebilirsiniz.

12. Raku Modülleri

Raku, genel amaçlı bir programlama dilidir. Aşağıdakiler dahil pek çok görevin üstesinden gelmek için kullanılabilir: metin işlemem, grafik, web, veritabanı, ağ protokolleri vb.

Tekrar kullanılabilirlik, programcıların her seferinde tekerleği yeniden icar etmelerini gerektirmeyen önemli bir kavramdır.

Raku tekrar kullanılabilir modüller yaratılmasına ve dağıtılmasına izin verir. Her bir modül, kurulduktan sonra tekrar tekrar kullanılabilen işlev kümesidir.

Zef Rakudo Star paketiyle gelen modül yöneticisidir.

Özel bir modül kurmak için terminal ekranına komutunu girmelisiniz:

zef install "modül adı"

Raku modül dizinine https://modules.perl6.org/ adresinden ulaşabilirsiniz.

12.1. Modüllerin Kullanımı

MD5, yaygın olarak kullanılan kriptografik özet fonksiyonudur. Girilen verinin boyutundan bağımsız olarak, 128-bit özet değer üretir.
MD5, veritabanında saklanan parolaların şifrelenmesi de dahil olmak üzere çeşitli uygulama alanları içerir. Yeni bir kullanıcı kayıt olduğunda, bilgileri düz metin olarak değil hashlenmiş olarak saklanır. Bunun arkasındaki mantık veritabanının bir saldırıya maruz kaldığı durumda, saldırganın kullanıcı bilgilerini görüntüleyememesidir.

MD5 algoritmasını kendiniz uygulamak zorunda değilsiniz, bunun için Raku modülü kullanıma hazırdır.

Öncelikle kuralım:
zef install Digest::MD5

Şimdi betiğimizi çalıştıralım:

use Digest::MD5;
my $password = "password123";
my $hashed-password = Digest::MD5.new.md5_hex($password);

say $hashed-password;

Gerekli modülü betiğimize çağırıdıktan sonra bunu use anahtar kelimesi ile yapıyoruz, md5_hex() fonksiyonu kullanılarak hash oluşturur.

Gerçek bir uygulamada tek başına MD5 hashlemesi yeterli olmayabilir, sözlük saldırılarına açıktır.
Salt ile kombine edilmelidir, https://en.wikipedia.org/wiki/Salt_(cryptography).

13. Unicode

Farklı karakter kodlama sistemlerinin birbiriyle tutarlı çalışmasını ve dünyadaki tüm yazım sistemlerinden metinlerin bilgisayar ortamında tek bir standart altında temsil edilebilmesini sağlamaktır.
UTF-8, 8-bitlik bir Unicode dönüşüm biçimidir. Unicode karakterlerini değişken sayıda 8 bitten oluşan gruplar ile kodlamakta kullanılır.

Karakterler şu şekilde tanımlanır:
Grapheme: Görsel temsil.
Code point: Karaktere atanan bir sayı.

13.1. Unicode Kullanmak

Unicode kullanarak karakterleri nasıl yazdırabileceğimizi görelim
say "a";
say "\x0061";
say "\c[LATIN SMALL LETTER A]";

Yukarıdaki üç satır, bir karakteri oluşturmak için farklı yollar gösteriyor:

  1. Karakteri doğrudan yazmak (grapheme)

  2. \x kullanarak ve yanına code point

  3. \c kullanarak ve yanına code point adı

Şimdi bir gülen surat yazdıralım
say "☺";
say "\x263a";
say "\c[WHITE SMILING FACE]";
İki -code points’i birleştiren örnek
say "á";
say "\x00e1";
say "\x0061\x0301";
say "\c[LATIN SMALL LETTER A WITH ACUTE]";

á karakteri için:

  • Benzersiz code point kullanarak \x00e1

  • veya code points ve a karakterinin kombosu şeklinde \x0061\x0301

Bazı örnekler:
say "á".NFC;
say "á".NFD;
say "á".uniname;
Çıktı
NFC:0x<00e1>
NFD:0x<0061 0301>
LATIN SMALL LETTER A WITH ACUTE

NFC benzersiz code point döndürür.
NFD karakter parçalanır ve code point ve karakter döndürülür.
uniname code point adı döndürülür.

Değişken adı olarak Unicode karakterler kullanılabilir:
my  = 1;
++;
say ;
Unicode matematiksel ifadeler için kullanılabilir:
my $var = 2 + ;
say $var;

14. Paralel, Eşzamanlı ve Asenkron Programlama

14.1. Paralellik

Normal koşullar altında bir programdaki tüm görevler sırayla çalışır.
Yapmaya çalıştığınız şey çok zaman almazsa bu sorun olmayabilir.

Neyse ki Raku, işleri paralel olarak yürütmenizi sağlayacak özelliklere sahiptir.
Bu aşamada paralellik aşağıdaki şeylerden biri anlamına gelebilir:

  • Görev Paralelliği Paralel olarak çalışan iki (veya daha fazla) işlem.

  • Veri Paralelliği Paralel olarak bir öğe listesi üzerinde yenilenen tek ifade.

İkincisi ile başlayalım.

14.1.1. Veri Paralelliği (Data Parallelism)

my @array = (0..50000);                     # Dizi nüfusu
my @result = @array.map({ is-prime $_ });   # Dizi üzerindeki her bir eleman için is-prime çağrılıyor
say now - INIT now;                         # Betiğin tamamlanma süresini yazdıralım.
Yukarudaki örnek göz önüne alındığında:

Sadece tek bir işlem yapıyoruz: @array.map({ is-prime $_ })
is-prime her bir dizi elemanı için çağırılıyor:
is-prime @array[0], is-prime @array[1] şeklinde.

Aynı anda birden çok dizi elamanı için is-prime çağırabiliriz.
my @array = (0..50000);                         # Dizi nüfusu
my @result = @array.race.map({ is-prime $_ });  # Dizi üzerindeki her bir eleman için is-prime çağrılıyor
say now - INIT now;                             # Betiğin tamamlanma süresini yazdıralım.

ifadede race kullanımına dikkat edelim. Bu metot bize dizi elelamanlarının paralel olarak yinelenmesini sağlayacaktır.

Her iki örneğide çalıştırdıktan sonra süreleri karşılaştırın.

race elemanların sırasını koruyamaz. Eğer bunu istiyorsanız race yerine hyper kullanın.

race
my @array = (1..1000);
my @result = @array.race.map( {$_ + 1} );
.say for @result;
hyper
my @array = (1..1000);
my @result = @array.hyper.map( {$_ + 1} );
.say for @result;

Her iki örneğide çalıştırırsanız birinin sıralı diğerinin sırasız olduğunu göreceksiniz.

14.1.2. Görev Paralelliği (Task Parallelism)

my @array1 = (0..49999);
my @array2 = (2..50001);

my @result1 = @array1.map( {is-prime($_ + 1)} );
my @result2 = @array2.map( {is-prime($_ - 1)} );

say @result1 eqv @result2;

say now - INIT now;
Yukarıdaki örnek göz önüne alındığında:
  1. 2 dizi tanımladık

  2. Her dizi için farklı işlem uygulandı ve sonuçlar değişkenlere kaydedildi.

  3. Ve sonuçların aynı olup olmadığı kontrol edildi.

Betik @array1.map( {is-prime($_ + 1)} ) işleminin bitmesini bekler
ve @array2.map( {is-prime($_ - 1)} ) işlemine geçer.

Dizilere uygulanan işlemler birbirine bağlı değildir.

O halde paralel kullanabiliriz.
my @array1 = (0..49999);
my @array2 = (2..50001);

my $promise1 = start @array1.map( {is-prime($_ + 1)} ).eager;
my $promise2 = start @array2.map( {is-prime($_ - 1)} ).eager;

my @result1 = await $promise1;
my @result2 = await $promise2;

say @result1 eqv @result2;

say now - INIT now;
Açıklama

start altyordamı kodu işleme alır ve bir promise döndürür.
Kod doğru şekilde çalışırsa, promise tutulur.
Kod bir istisna fırlatırsa, promise kırılmış olacaktır.

await altyordamı bir promise bekler.
Tutulan bir değer döndürülürse alacaktır.
Eğer kırılmış ise istisna fırlatacaktır.

Paralellik her zaman iş parçacığına yük ekler. Bu yük, hesaplama hızındaki kazançlarla dengelenmemişse betik yavaş görünür.
Bu nedenle, basit betikler için race, hyper, start ve await kullanmak aslında onları yavaşlatabilir.

14.2. Eşzamanlılık ve Asenkron

Eşzamanlılık ve asenkron programlama hakkında bilgi için https://docs.perl6.org/language/concurrency adresine bakınız.

15. Native Çağrı Arayüzü (Native Calling Interface)

Raku bize C kütüphanelerini kullanma imkanı verir, bunu Native Calling Interface kullanarak yaparız. NativeCall, Raku ile gelen standart bir modüldür ve işi kolaylaştırmak için işlevsellik sunar.

15.1. Bir Fonksiyon Çağırmak

hellofromc adlo fonksiyonu olan aşağıdaki C kodunu göz önünde bulundurun. Bu fonksiyon ekrana Hello from C yazar. Parametre almaz ve geriye değer döndürmez.

ncitest.c
#include <stdio.h>

void hellofromc () {
  printf("Hello from C\n");
}

İşletim sisteminize göre aşağıdaki komutları çalıştırarak bir C kütüphanesi elde edelim.

Linux:
gcc -c -fpic ncitest.c
gcc -shared -o libncitest.so ncitest.o
Windows:
gcc -c ncitest.c
gcc -shared -o ncitest.dll ncitest.o

C kütüphanemiz derlendiği dizinde oluşturulmuş oldu, şimdi bir Raku dosyası oluşturalım ve aşağıdaki kodu yazarak çalıştıralım.

ncitest.pl6
use NativeCall;

constant LIBPATH = "$*CWD/ncitest";
sub hellofromc() is native(LIBPATH) { * }

hellofromc();
Açıklama

İlk olarak NaticeCall modülünü betiğimize ekledik.
Daha sonra C kütüphanemizin yolunu tutan LIBPATH adında bir sabit oluşturduk.
$*CWD geçerli çalışma dizinini döndürür.
Ardından adı hellofromc olan yeni bir altyordam oluşturduk, bu C fonksiyonuyla aynı adı taşıyan bir sarmalayıcı.
Bunu is native ile yaptık.
Son olarak Raku altyordamımızı çağırdık.

15.2. Fonksiyonu Yeniden Adlandırma

Yukarıdaki bölümde C kütüphanesinin is native kullanılarak nasıl çağırıldığını gördük.

Bazı durumlarda Raku altyordamının adını değiştirmek isteyebiliriz.
Bunu yapmak için is symbol özelliğini kullanırız.

Yukarıdaki Raku betiğini değiştirelim ve altyordamımızın adını hellofromc yerine hello yapalım.

ncitest.pl6
use NativeCall;

constant LIBPATH = "$*CWD/ncitest";
sub hello() is native(LIBPATH) is symbol('hellofromc') { * }

hello();
Açıklama

Raku altyordamının C fonksiyonundan farklı bir adı varsa is symbol özelliği ile orjinal C fonksiyonunun ismi kullanılmalıdır.

15.3. Geçici Argümanlar

Aşağıda değiştirilmiş C kütüphanesini derleyin ve aşağıda bulunan Raku betiğini çalıştırın. C’de char* Raku’da Str

ncitest.c
#include <stdio.h>

void hellofromc (char* name) {
  printf("Hello, %s! This is C!\n", name);
}
ncitest.pl6
use NativeCall;

constant LIBPATH = "$*CWD/ncitest";
sub hello(Str) is native(LIBPATH) is symbol('hellofromc') { * }

hello('Jane');

15.4. Dönüş Değeri

2 tam sayı değerini parametre olarak alan ve toplamlarını döndüren basit bir hesap makinesi yapalım. C kütüphanesini derleyin ve Raku betiğini çalıştırın.

ncitest.c
int add (int a, int b) {
  return (a + b);
}
ncitest.pl6
use NativeCall;

constant LIBPATH = "$*CWD/ncitest";
sub add(int32,int32) returns int32 is native(LIBPATH) { * }

say add(2,3);

C’de int, Raku’da int32

15.5. Tipler

Son Raku betiğimizde neden int yerine int32 kullanıldığını kendimize sorabiliriz.
Int, Rat gibi bazı Raku veri tipleri, bir C fonksiyonunda parametre olarak veya dönüş tipi olarak kullanılamaz.
Kullanılabilmesi için Raku’da C’deki ile aynı tipte olması gerekir.

Raku’da C ile eşleşen birçok veri tipi vardır.

C Tipi Raku Tipi

char

int8

int8_t

short

int16

int16_t

int

int32

int32_t

int64_t

int64

unsigned char

uint8

uint8_t

unsigned short

uint16

uint16_t

unsigned int

uint32

uint32_t

uint64_t

uint64

long

long

long long

longlong

float

num32

double

num64

size_t

size_t

bool

bool

char* (String)

Str

Arrays: Örnek olarak int* (int dizisi) and double* (double dizisi)

CArray: Örnek olarak CArray[int32] ve CArray[num64]

Native Calling Interface hakkında daha fazla bilgiye https://docs.perl6.org/language/nativecall adresinden ulaşabilirsiniz.

16. Topluluk

  • #perl6 IRC kanalı. IRC oldukça aktiftir. Hakkında daha fazla bilgi için: https://perl6.org/community/irc

  • p6weekly Perl 6 ve yapılan değişiklikler ile ilgili bir haftalık bülten.

  • pl6anet Perl 6’ya odaklanan blog yayınlarını okuyabilirsiniz.

  • /r/perl6 Perl 6 alt redditine üye olabilirsiniz.