Haskell saf işlevsel bir dildir bu özelliğiyle matematiksel bir temele dayanır ve diğer programlama dillerinde onlarca satırda yapacağınız bir hesaplamayı haskellde birkaç adımda yapabilirsiniz. Haskell'in en önemli özelliği lazy evalution yapısıdır, bu yapı eşitliklerin sadece gereken anlarda, gerektiği kadar çözümlenmesine dayanmaktadır. Bu sayede bellek tasarrufu ve dolayısıyla performans sağlanmakta ve yanlış hesaplamaların önüne geçilmektedir. Haskell bir yorumlayıcı vasıtasıyla yorumlanmaktadır, derlenmez. Bu yorumlayıcılarım en ünlüsü Hugs'dur. Ancak JCreator java derleyicisiyle entegre çalışabilmesi sayesinde programlarınızı bu derleyici vasıtasıyla derleyebilirsiniz.
Tembel (lazy): Tembel dillerde eşitlikler, gerekmedikleri sürece çözümlenmezler.
Sadece gerektiğinde çözümlenirler. Bu bakımdan Haskell, kesin belirtimli (strict)
dillerden farklıdır.
Saf (pure): Haskell, yan etkiye (side effect) izin vermediğinden dolayı saftır.
Programlama terimi olarak 'yan etki', evrensel (global) bir değişkeni
etkilemek veya evrensel bir değişkenin etkisinde kalmak anlamında kullanılır.
Sorunlara neden olduğundan dolayı mümkün olduğunca kaçınılması gereken bir durumdur.
Örneğin bir fonksiyon içinde global değişkenler kullanıldığında, fonksiyon parametreleri
aynı değere sahip olmasına rağmen, fonksiyon her seferinde farklı bir sonuç
döndürebileceğinden dolayı, yan etkiye açık hale gelmiş olur.
Evrensel değişkenlere (örneğin ekrana, paralel porta v.b.) erişimi tamamen
engellemek, bir programlama dilini işlevsiz kılacağı için bu tip işlemler,
monads olarak adlandırılan ve programın saflığını bozmayacak korumalı alanlarda
güvenli bir şekilde yapılır.
İşlevsel (functional): Haskell, işlevsel bir programlama dilidir çünkü her bir Haskell
programı, saf bir matematik fonksiyonunun karşılığıdır. Haskell, matematik bir modele
dayanır. Yapılacak işleri komut listesi şeklinde alan C gibi komut dillerinden (imperative)
farklı olarak Haskell'de satır sırasının bir önemi yoktur.
Haskell Yorumlayıcıları ve Derleyicileri
---------------------------------------
* Hugs
Etkileşimli arayüzü olan, Haskell98 standartlarını destekleyen bir yorumlayıcı.
Derleme yapmaz.
apt-get install hugs
* GHC
Haskell98 standartlarına uyumlu derleyici ve yorumlayıcı.
Yorumlayıcısı Hugs'a göre daha yavaş ama daha yetenekli.
apt-get install ghc5 ( sarge için )
apt-get install ghc6 ( etch için )
* NHC
Az kullanılan ve etkileşimli arayüzü olmayan bir derleyici ama GHC'ye göre
daha ufak ve hızlı çalışan kod üretiyor.
apt-get instal nhc98
En uygun seçenek GHC olarak görünüyor.
GHC kullanımı
-------------
* main fonksiyonu olan Main.hs adlı programı derlemek için:
ghc --make Main.hs -o main
--make: bu seçenek, derlenecek olan dosyanın kütüphane değil, program olduğunu
belirtiyor. Bu nedenle kod, gerekli olan bütün kütüphaneler ile birlikte derleniyor.
-o: bu seçenek ile, oluşacak olan çalışabilir dosyanın adı veriliyor.
* Etkileşimli modda çalıştırmak için:
ghci
veya
ghc -interactive
* Etkileşimli modda modül ve dosya yüklemek için:
:load dosya
* Extension'ların açık olması için yorumlayıcıyı başlatırken
-fglasgow-exts
Bu seçenek verilmezse yorumlayıcı Haskell98 modunda çalışır.
Bu durumda bütün extension'lar kapalıdır.
Dilin Temelleri
--------------
* Tembel (lazy)
Eşitlikler, ancak ihtiyaç duyulduğu anda, sadece gereken kadar çözümlenir.
Fonksiyonlar, değerleriyle değil isimleriyle çağrılır.
'call by name' vs 'call by value'
* Büyük-küçük harfe duyarlı (case-sensitive)
Haskell, bir çok dil gibi büyük-küçük harf ayrımı yapmasının yanında, bir de fazladan,
ifadelere, büyük-küçük harfle başlamasına göre farklı davranır. Haskell'de
değerler (values), küçük harf ile, tipler (types), büyük harf ile başlar.
Fonksiyonların da bir değer olduğunu unutma!
* Pure (saf)
Bir fonksiyon, çalışması esnasında global bir değişkeni etkiliyor veya global bir
değişkenin etkisinde kalıyorsa yan etki (side-effect) oluşur. Ekrana birşey yazmak,
bir dosyadan okuma yapmak yan etkisi olan işlem örnekleridir.
Haskell'de değerleri değişebilen değişkenler yoktur. Bir değer atandıktan sonra
bir daha değişmez. Bu nedenle f fonksiyonu, a argumanı ile her çağrıldığında hep
aynı sonucu üretir çünkü programın her yerinde a, aynı değere sahiptir ve
f fonksiyonunun üreteceği sonuç, sadece bu argumana bağlıdır; global bir değişken,
fonksiyonun işleyişini etkileyemeyecektir.
* Aritmatik
Etkileşimli modda yorumlayıcıyı açıp (örneğin ghci ile) basit maematik işlemleri
yapabiliriz.
Prelude> 2 * 4
8
Prelude> 4 / (4-3)
4.0
Prelude> sqrt 6
2.449489742783178
Prelude> 4^5
1024
* Tuple
Tuple'ların elaman sayısı sabittir. Her bir elamanı farklı tipte olabilir.
Prelude> (3,5,"merhaba")
(3,5,"merhaba")
Prelude> fst (4,5)
4
Prelude> snd (4,"merhaba")
"merhaba"
* Listeler
* Listeler, tuple'lara benzer ama bütün elemanları aynı tiptedir.
Prelude> [4,5]
[4,5]
Prelude> ["merhaba","dünya"]
["merhaba","d\252nya"]
* : işaretine 'cons' operatörü denir. Bu opeartörle yapılan işleme
'consing' denir. "constructing" (inşa etmek) kelimesinden gelir.
Bir list'e eleman ekleyerek yeni bir list meydana getirmek için
kullanılır.
Prelude> 3:[2,5,7]
[3,2,5,7]
Prelude> [(3,"merhaba"),(7,"dünya")]
[(3,"merhaba"),(7,"d\252nya")]
Prelude> [[4,5],[1,2]]
[[4,5],[1,2]]
* head, tail ve lenght fonksiyonları...
Prelude> head [4,2,8]
4
Prelude> tail [4,2,8]
[2,8]
Prelude> length [4,2,8]
3
Prelude> length (tail [4,2,8])
2
* String
* Haskell'de string, karakterlerden oluşan bir listedir
Prelude> 'm':'e':'r':'h':'a':'b':'a':[]
"merhaba"
Prelude> "merhaba " ++ "dünya"
"merhaba d\252nya"
* Bir değeri, string'e çevirmek için show(),
string değeri, string olmayan değere çevirmek için read()
fonksiyonu kullanılır.
Prelude> "2 + 5 = " ++ show(2+5)
"2 + 5 = 7"
Prelude> read "8" - 2
6
* Basit liste fonksiyonları
* map : Bir fonksiyona, bir listenin elemanlarını sırası ile arguman
olarak verip, yeni bir liste elde eder
Prelude> map Char.toUpper "merhaba"
"MERHABA"
* filter: listeyi filtrelemek için kullanılır
Prelude> filter Char.isLower ['M','e','R','H','a','B','a']
"eaa"
* foldr: bu fonksiyon 3 arguman alır. Bir fonksiyon, ilk değer ve bir liste...
işleme sağ taraftan başlar.
Prelude> foldr (+) 1 [2,3,4]
10
Prelude> foldr (-) 1 [2,3,4]
2
(2 - (3 - (4 - 1)))
(2 - (3 - 3))
(2 - 0)
2
* foldl: foldr'ye benzer. Ters sırada işlem yapar, soldan başlar.
Prelude> foldl (-) 1 [2,3,4]
-8
(((1 - 2) - 3) - 4)
((-1 -3) - 4)
(-4 - 4)
-8
foldl daha verimli çalışmasına karşın, sonsuz listelerle işlem yapamaz.
İşleme son elemandan başladığı için daha ilk işlemde son elemanın ne olduğunun
biliniyor olması gerekir. foldr ise sonsuz listelerle birlikte kullanılabilir.
* Kaynak kod dosyası
* Aşağıdaki kodu herhangi bir metin editörü ile yazıp kaydet.
module Test
where
x = 3
y = (5,"merhaba")
z = x * fst y
Bu bir modül olduğu için dosya adı da, modül adıyla aynı olmalı.
Yani Test.hs olarak kaydedilmeli.
* Modulu yüklemek için yorumlayıcıyı başlatırken
ghci Test.hs
* veya yorumlayıcı başlatıldıktan sonra
Prelude>:load Test.hs
veya
Prelude>:l Test.hs
* Yüklü olan bir modülü yeniden yüklemek için
Test>:reload
veya
Test>:r
* Yukarıdaki modül yüklendikten sonra şu neticeler elde edilir:
Test>x
3
Test>y
(5,"merhaba)
Test>z
15
* Bir programı derlemek için programın modül adı Main olmalı ve içinde main
fonksiyonu bulunmalı
module Main
where
main = putStrLn "merhaba"
* Bu dosya Text.hs olarak kaydedildikten sonra
ghc --make Test.hs -o test
./test
Fonksiyonlar
------------
* Basit bir fonksiyon
kare x = x * x
Bu fonksiyonun adı 'kare'dir.
Bir tane arguman olmaktadır, o da x...
kare x fonksiyonunun değeri x * x'tir.
Test>kare 5
25
Test>kare (-5)
25
Negatif sayıları parantez içinde ver yoksa - işareti nedeniyle çıkarma işlemi
yapılmaya çalışılıyor ki bu da hataya neden oluyor.
* if...then...else...
Her if/then için bir else olmak zorundadır.
isaret x = if x<0
then -1
else if x>0
then 1
else 0
Test>isaret 5
1
Test>isaret (-5)
-1
Test>isaret 0
0
* case
f x =
case x of
1 -> 0
2 -> 2
3 -> 5
_ -> x * 2
Test> f 1
0
Test> f 3
5
Test> f 7
14
* Aynı fonksiyon, birkaç farklı şekilde tanımlanabilir. Argumana göre
uygun olan hali kullanılır.
f 1 = 2
f 2 = 3
f 3 = 5
f _ = -1
Test>f 1
2
Test>f 3
5
Test>f 6
-1
* İç içe fonksiyon kullanımı
f1 (f2 5)
veya Haskell'e daha uygun bir biçimle
(f1.f2) 5
* Bazı built-in functionlar
Test> sqrt 4
2.0
Test> null []
True
Test> null [3,4,5]
False
Test> id 5
5
Test> id "merhaba"
"merhaba"
Test> fst (5,4)
5
Test> snd (5,4)
4
Test> head [6,3,2,5]
6
Test> tail [6,3,2,5]
[3,2,5]
Test> [5,3,7] ++ [1,5,0]
[5,3,7,1,5,0]
Test> 4 == 4
True
Test> [4,5,6] /= [4,5,6]
True
Test> [4,5,6] == [4,6,5]
False
* let...in...
f x =
let
a = 1
b = 2
in (x*(a-b),x*(b-a))
Test> f 3
(-3,3)
* infix
Sembol olarak değerlendirilen fonksiyonlara, infix fonksiyonlar denir.
Bunları infix modda değil de non-infix modda kullanmak icin () arasına alınır
infix mod:
Prelude> 4 + 5
9
non-infix mod:
Prelude> (+) 4 5
9
non-infix fonksiyonları infix modda kullanmak için ise `` arasına alınır.
non-infix mod:
Prelude> map Char.toUpper "merhaba"
"MERHABA"
infix mod:
Prelude>Char.toUpper `map` "merhaba"
"MERHABA"
Notlar
------
* Tek satırlık notlar için -- kullanılır
f x = x * x -- f fonksiyonu tanımlandı
* Bir kaç satırlık not için yazılanlar {- ve -} arasına alınır
{- bu kısımda
bazı notlar
yer almaktadır -}
Recursion
---------
* örnek 1:
fact 1 = 1
fact n = n * fact (n-1)
* örnek 2:
uzunluk [] = 0
uzunluk (x:xs) = 1 + uzunluk xs
* örnek 3:
filtre p [] = []
filtre p (x:xs) =
if p x:
then x : filtre p xs
else filtre p xs
Test>filtre Char.isUpper "meRhABa"
"RAB"
Types (tipler)
-------------
* Haskell, static type cheking kullanır, yani bütün ifadeler için bir tip belirlenir.
Bir arguman için olması gerekenden farklı tipte bir değer kullanılırsa, derleme anında
hata oluşur.
* Bütün ifadeler için tip belirlenmesi zorunlu olmasına karşın, bunu programcı belirtmek
zorunda değildir. Tip belirtilmediğinde, en uygun olan tip otomatik olarak seçilir.
* Bir değerin tipini öğrenmek için etkileşimli modda :type veya :t kullanılır
Prelude>:type 'a'
Char
Prelude>:t "merhaba"
[Char]
Prelude>:t 1 == 2
Bool
Prelude>:t 4
forall t. (Num t) => t
Prelude>:t 4.0
forall t. (Fractional t) => t
Prelude>:t fst
for all a b. (a,b) -> a
* Değerin tipi, programcı tarafından da :: kullanılarak belirtilebilir
Prelude>:t 4 :: Int
Int
Prelude>:t 4 :: Double
Double
Prelude>:t "merhaba" :: String
String