Haskel Nedir? ------------ Tembel (lazy) ve saf işlevsel (pure functional) bir programlama dilidir. 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 ghc ( jessie için ) 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 Data.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