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.
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
Bu belgeye katkıda bulunmak isterseniz:
Tüm görüşeriniz memnuniyetle karşılanmaktadır:
-
[email protected] -İngilizce
Bu eseri beğendiyseniz, kaynağına göz atabilirsiniz Github.
-
Almanca: http://de.perl6intro.com
-
Bulgarca: http://bg.perl6intro.com
-
Çince: http://zh.perl6intro.com
-
Flemenkçe: http://nl.perl6intro.com
-
Fransızca: http://fr.perl6intro.com
-
İngilizce: http://perl6intro.com
-
İspanyolca: http://es.perl6intro.com
-
İtalyanca: http://it.perl6intro.com
-
Japonca: http://ja.perl6intro.com
-
Portekizce: http://pt.perl6intro.com
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)
-
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
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.
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.
-
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.
-
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:
|
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 |
|
Bağlama(Infix) |
Terimler arasında |
|
Sonek(Postfix) |
Terimden sonra |
|
Başında ve sonunda(Circumfix) |
Terimin etrafında |
|
Sonrasında, başında ve sonunda(Postcircumfix) |
Terimin öncesinde ve etrafında |
|
1.7.1. Tanımlayıcılar
Tanımlayıcı, tanımlanan veriye verilen isimdir.
-
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 |
|
|
|
|
|
|
|
|
|
|
-
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 |
---|---|---|---|---|
|
|
Ekleme |
|
|
|
|
Çıkarma |
|
|
|
|
Çarpma |
|
|
|
|
Kuvvet |
|
|
|
|
Bölme |
|
|
|
|
Tam sayı bölme |
|
|
|
|
Modül |
|
|
|
|
Bölünebilirlik |
|
|
|
|
|||
|
|
En büyük ortak bölen |
|
|
|
|
En küçük ortak kat |
|
|
|
|
Numerik eşitlik |
|
|
|
|
Numerik eşitsizlik |
|
|
|
|
Küçükse |
|
|
|
|
Büyükse |
|
|
|
|
Küçük veya eşitse |
|
|
|
|
Büyük veya eşitse |
|
|
|
|
Karakter dizisi(String) eşitliği |
|
|
|
|
String eşit değilse |
|
|
|
|
Atama |
|
|
|
|
Stringleri birbirine bağlar |
|
|
|
|
|||
|
|
String çoğaltır |
|
|
|
|
|||
|
|
Akıllı eşleme |
|
|
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
Arttırma |
|
|
|
Arttırma |
|
|
|
|
|
Azaltma |
|
|
|
Azaltma |
|
|
|
|
|
İşlenen değeri numerik sonuca zorlar |
|
|
|
|
|||
|
|
|||
|
|
İşlenen değeri negatif numerik sonuca zorlar |
|
|
|
|
|||
|
|
|||
|
|
İşlenen değeri mantıksal(boolean) sonuca zorlar |
|
|
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
İşlenen değeri mantıksal sonuca zorlar ve tersini alır |
|
|
|
|
Aralık oluşturucu |
|
|
|
|
Aralık oluşturucu |
|
|
|
|
Aralık oluşturucu |
|
|
|
|
Aralık oluşturucu |
|
|
|
|
Aralık oluşturucu |
|
|
|
|
Tembel liste oluşturucu |
|
|
|
|
Düzleştirme |
|
|
|
|
2.2. Ters Operatörleri
Herhangi bir işlemden önce R
kullanmak işlemi tersine çevirecektir.
Operasyon | Sonuç | Ters Operatörü | Sonuç |
---|---|---|---|
|
|
|
|
|
|
|
|
2.3. İndirgeme Operatörleri
Listelerle çalışırlar ve []
ile çevrelenirler.
Operasyon | Sonuç | İndirgeme Operatörü | Sonuç |
---|---|---|---|
|
|
|
|
|
|
|
|
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.
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. |
my $age = 17;
say $age.is-prime;
True
Integer verilere uygulanabilen metotların listesi için https://docs.perl6.org/type/Int adresine bakabilirsiniz. |
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
.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]]
[1 x]
[2 y]
[3 z]
Diziler hakkında daha fazla bilgiye https://docs.perl6.org/type/Array adresinden ulaşabilirsiniz. |
3.3. Hashler
my %capitals = ('UK','London','Germany','Berlin');
say %capitals;
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
.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.
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;
|
|
|
|
|
|
||
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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:
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.
my Int $var := 123;
say $var;
$var = 999;
say $var;
Çıktı
123
Cannot assign to an immutable value
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
.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.
my $name = 'Neo';
run 'echo', "hello $name";
shell "ls";
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:
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.
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.
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.
sub squared ($x) returns Int {
return $x ** 2;
}
say "1.2 squared is equal to " ~ squared(1.2);
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
|
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.
my @array = <1 2 3 4 5>;
sub squared($x) {
$x ** 2
}
say map(&squared,@array);
(1 4 9 16 25)
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.
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.
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;
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.
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.
my $lazylist = (1 ... Inf);
say $lazylist;
Bu liste 1’den sonsuza kadar olan herhangi bir tam sayıyı istendiği takdirde döndürebilir.
my $lazylist = (0,2 ... 10);
say $lazylist;
Bu tembel liste istediği takdirde (0, 2, 4, 6, 8, 10) elamaları döndürebilir.
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 Durmaz
Durur
|
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.
my $var = 7;
say $var;
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]
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.
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.
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)
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
my Int $age = 21;
die "Error !";
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.
if 'Temperature: 13' ~~ m/ \: / {
say "The string provided contains a colon :";
}
if 'Age = 13' ~~ m/ '=' / {
say "The string provided contains an equal character = ";
}
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.
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;
}
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
$/
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. |
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";
}
[email protected] is a valid email
<: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>+
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
say "a";
say "\x0061";
say "\c[LATIN SMALL LETTER A]";
Yukarıdaki üç satır, bir karakteri oluşturmak için farklı yollar gösteriyor:
-
Karakteri doğrudan yazmak (grapheme)
-
\x
kullanarak ve yanına code point -
\c
kullanarak ve yanına code point adı
say "☺";
say "\x263a";
say "\c[WHITE SMILING FACE]";
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
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.
my $Δ = 1;
$Δ++;
say $Δ;
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.
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.
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
hyper
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;
-
2 dizi tanımladık
-
Her dizi için farklı işlem uygulandı ve sonuçlar değişkenlere kaydedildi.
-
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.
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;
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.
#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.
gcc -c -fpic ncitest.c
gcc -shared -o libncitest.so ncitest.o
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.
use NativeCall;
constant LIBPATH = "$*CWD/ncitest";
sub hellofromc() is native(LIBPATH) { * }
hellofromc();
İ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.
use NativeCall;
constant LIBPATH = "$*CWD/ncitest";
sub hello() is native(LIBPATH) is symbol('hellofromc') { * }
hello();
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
#include <stdio.h>
void hellofromc (char* name) {
printf("Hello, %s! This is C!\n", name);
}
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.
int add (int a, int b) {
return (a + b);
}
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 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Arrays: Örnek olarak |
|
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.