[
  {
    "path": "README.md",
    "content": "> This is the Turkish translation of Yann Esposito's article [Learn Haskell Fast and Hard](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/).\n\n> Yann Esposito'nun [Learn Haskell Fast and Hard](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/) başlıklı yazısının Türkçe çevirisidir.\n\n# Zor Yoldan Haskell\n\n> TL, DR (Çok uzundu okumadım): Haskell öğrenmek için kısa ve yoğun bir rehber.\n\n#### İçindekiler:\n* [Giriş](#1-giri%C5%9F)\n    * [Kurulum](#11-kurulum)\n    * [Korkmayın](#12-korkmay%C4%B1n)\n    * [Haskell'e Giriş](#13-haskelle-giri%C5%9F)\n        * [Fonksiyon tanımı](#131-fonksiyon-tan%C4%B1m%C4%B1)\n        * [Tip örneği](#132-tip-%C3%B6rne%C4%9Fi)\n* [Temel Haskell](#2-temel-haskell)\n    * [Notasyon](#21-notasyon)\n        * [Aritmetik](#aritmetik)\n        * [Mantıksal](#mant%C4%B1ksal)\n        * [Üslü Sayılar](#%C3%9Csl%C3%BC-say%C4%B1lar)\n        * [Listeler](#listeler)\n        * [Karakter Dizileri](#karakter-dizileri)\n        * [Demetler *(Tuple)*](#demetler-tuple)\n        * [Parantezlerle Baş Etmek](#parantezlerle-ba%C5%9Fa-%C3%87%C4%B1kmak)\n    * [Fonksiyonlar için Faydalı Notasyonlar](#22-fonksiyonlar-i%C3%A7in-faydal%C4%B1-notasyonlar)\n* [Zor Kısım](#3-zor-k%C4%B1s%C4%B1m)\n    * [Fonksiyonel Stil](#31-fonksiyonel-stil)\n        * [Üst Derece Fonksiyonlar](#311-%C3%9Cst-derece-fonksiyonlar)\n    * [Tipler](#32-tipler)\n        * [Tip Çıkarımı](#321-tip-%C3%87%C4%B1kar%C4%B1m%C4%B1)\n        * [Tip Oluşturma](#322-tip-olu%C5%9Fturma)\n        * [Özyinelemeli Tipler *(Recursive types)*](#323-%C3%96zyinelemeli-tipler-recursive-types)\n        * [Ağaçlar](#324-a%C4%9Fa%C3%A7lar)\n    * [Sonsuz Yapılar](#33-sonsuz-yap%C4%B1lar)\n* [Çok Zor Kısım](#4-%C3%87ok-zor-k%C4%B1s%C4%B1m)\n    * [IO ile Baş Etmek](#41-io-ile-ba%C5%9F-etmek)\n    * [IO'nun Püf Noktası](#42-ionun-p%C3%BCf-noktas%C4%B1)\n    * [Monad](#43-monad)\n        * [Maybe Monad'ı](#431-maybe-monad%C4%B1)\n        * [Liste Monad'ı](#432-liste-monad%C4%B1)\n* [Ekler](#5-ekler)\n    * [Sonsuz Ağaçlar Hakkında](#51-sonsuz-a%C4%9Fa%C3%A7lar-hakk%C4%B1nda)\n\n***\n\nTüm geliştiricilerin Haskell öğrenmesi gerektiğine inanıyorum. Herkesin süper Haskell ninjası olması gerektiğini düşünmüyorum, ama herkes Haskell'in sahip olduğu farklı yönleri görmeli; Haskell öğrenmek zihninizi acar.\n\nAnaakım diller aynı temelleri paylaşırlar:\n* değişkenler\n* döngüler\n* işaretçiler *(pointer)* [^fn-1]\n* veri yapıları, nesneler ve sınıflar (genellikle)\n\nAma Haskell çok farklıdır. Bu dil daha önceden hiç duymamış olduğum bir sürü kavram kullanıyor. Bu kavramların çoğu daha iyi bir programcı olmanızda yardımcı olacaktır.\n\nHaskell öğrenmek zor olabilir, benim için öyleydi. Bu yazıda ben öğrenirken eksik olan şeyleri size sunmaya çalışacağım.\n\nBu yazıyı takip etmek zor olacak ve bunu bilerek yapıyorum; Haskell öğrenmenin kısayolu yoktur, zordur ve çaba ister. Ama bunun iyi bir şey olduğuna inanıyorum; Haskell, zor olduğu için ilginç.\n\nHaskell öğrenmenin klasik yolu şu iki kitabı okumaktır. İlk önce [\"Learn You a Haskell\"](http://learnyouahaskell.com/) (Haskell Öğrenin) ve sonrasında da [\"Real World Haskell\"](http://www.realworldhaskell.org/) (Gerçek Dünyada Haskell). Ben de bunun doğru yol olduğuna inanıyorum. Haskell'in doğru düzgün öğrenmek için, bu kitapları ayrıntılı şekilde okumalısınız.\n\nTersi şekilde, bu yazı Haskell'in ana konularının oldukça kısa ve yoğun bir özeti. Kendim Haskell öğrenirken ihtiyaç duyup bulamadığım bazı bilgileri de ekledim.\n\nBu yazının beş bölümü var:\n* Giriş: Haskell'in insancıl olabildiğini göstermek için bir kısa örnek.\n* Temel Haskell: Haskell söz dizimi ve bazı temel kavramlar.\n* Zor Bölüm:\n    * Fonksiyonel stil; imperatif stilden fonksiyonel stile kademeli bir örnek.\n    * Tipler; tipler ve standard bir ikili ağaç *(binary tree)* örneği.\n    * Sonsuz Yapılar; sonsuz bir ikili ağacı işleyin.\n* Çok Zor Bölüm:\n    * IO ile baş edin; minimal bir örnek.\n    * IO hileleri açıklaması, IO'yu anlamak için ihtiyaç duyduğum gizli detay\n    * Monad'ler, inanılmaz genellenebilirlikleri\n* Ek:\n    * Sonsuz ağaçlar hakkında matematik tabanlı bir tartışma.\n\n> Her `.lhs` ile biten bir dosya isimli ayırıcı gördüğünüzde, dosyaya ulaşmak için tıklayabilirsiniz. Dosyayı `dosyaismi.lhs` diye kaydederseniz, `runhaskell dosyaismi.lhs` komutuyla çalıştırabilirsiniz. Bazıları çalışmayabilir ama çoğu çalışacaktır. Aşağıda bir link görebilirsiniz.\n[01_basic/10_Introduction/00_hello_world.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/01_basic/10_Introduction/00_hello_world.lhs)\n(Çevirmen notu: Kodlardaki karakter dizileri Türkçeleştirilmiş, ancak değişken isimleri aynı bırakılmıştır. İndirilen kodlar İngilizce kaynaktan olup Türkçeleştirilmemiş olacaktır.)\n\n# 1. Giriş\n\n## 1.1. Kurulum\n![Haskell](http://yannesposito.com/Scratch/img/blog/Haskell-the-Hard-Way/Haskell-logo.png)\n\nAraçlar:\n* `ghc`: `C`'deki gcc gibi bir derleyici.\n* `ghci`: İnteraktif Haskell yorumlayıcısı. (REPL)\n* `runhaskell`: Bir programı derlemeden çalıştırmak için kullanılır. Kolaydır, ama derlenen programlara göre çok yavaştır.\n\n## 1.2. Korkmayın\n![Scream](http://yannesposito.com/Scratch/img/blog/Haskell-the-Hard-Way/munch_TheScream.jpg)\n\nHaskell hakkındaki pek çok kitap/makale az bilinen bir formülü (quick sort, Fibonacci, vs.) yazmakla başlıyor, bense tam tersini yapacağım. İlk önce size Haskell'in süper güçlerini göstermeyeceğim. Haskell ve diğer programlama dilleri arasındaki benzerliklerle başlayacağım. Zorunlu \"Merhaba Dünya\" programıyla başlayalım.\n```haskell\nmain = putStrLn \"Merhaba Dünya!\"\n```\nÇalıştırmak için, kodu `merhaba.hs` olarak kaydedip şu komutları kullanabilirsiniz:\n```\n~ runhaskell ./merhaba.hs\nMerhaba Dünya!\n```\nDoğrudan kaynak kodunu da indirebilirsiniz. Aşağıdaki komutların hemen altında linki görüp, `00_hello_world.lhs` olarak kaydedip bu komutlarla çalıştırabilirsiniz:\n```\n~ runhaskell 00_hello_world.lhs\nHello World!\n```\n[01_basic/10_Introduction/00_hello_world.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/01_basic/10_Introduction/00_hello_world.lhs)\n\n***\n\n[01_basic/10_Introduction/10_hello_you.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/01_basic/10_Introduction/10_hello_you.lhs)\nŞimdi, adınızı soran ve aldığı cevapla size \"Merhaba\" diyen bir program yazalım:\n```haskell\nmain = do\n    print \"Adiniz nedir?\"\n    name <- getLine\n    print (\"Merhaba \" ++ name ++ \"!\")\n```\nÖncelikle, bunu birkaç imperatif dildeki benzer programlarla karşılaştıralım:\n```python\n# Python\nprint \"Adiniz nedir?\"\nname = raw_input()\nprint \"Merhaba %s!\" % name\n```\n\n```ruby\n# Ruby\nputs \"Adiniz nedir?\"\nname = gets.chomp\nputs \"Merhaba #{name}!\"\n```\n\n```c\n// In C\n#include <stdio.h>\nint main (int argc, char **argv) {\n    char name[666]; // <- musibetli sayi!\n    // Adim 665 karakterden fazlaysa ne olacak?\n    printf(\"Adiniz nedir?\\n\");\n    scanf(\"%s\", name);\n    printf(\"Merhaba %s!\\n\", name);\n    return 0;\n}\n```\n\nYapı aynı, ama söz dizimsel farklılıklar var. Bu yazının ana kısmı bu farkların sebebini açıklamak üzerine olacak.\n\nHaskell'de bir `main` fonksiyonu vardır ve her nesnenin bir tipi vardır. `main`'in tipi `IO ()`'dur. Bu, `main` yan etkilerde bulunacak demektir.\n\nŞimdilik, Haskell'in anaakım imperatif dillere benzer görünebileceğini hatırlamanız yeterli.\n\n[01_basic/10_Introduction/10_hello_you.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/01_basic/10_Introduction/10_hello_you.lhs)\n\n***\n[01_basic/10_Introduction/20_very_basic.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/01_basic/10_Introduction/20_very_basic.lhs)\n\n## 1.3. Haskell'e Giriş\n![Very Basic](http://yannesposito.com/Scratch/img/blog/Haskell-the-Hard-Way/picasso_owl.jpg)\n\nDevam etmeden önce, Haskell'in bazı temel özelliklerinin farkına varmanız gerekiyor.\n\n#### Fonksiyonel\nHaskell fonksiyonel bir dildir. Eğer imperatif bir dilde geçmişiniz varsa, yeni bir sürü şey öğrenmeniz gerekiyor. Umarım bu yeni kavramlar size imperatif dillerde program yazarken bile yardımcı olur.\n\n#### Akıllı Statik Tip Sistemi\n\nTip sistemi, `C`'de, `C++`'ta, `Java`'da olduğu gibi sizi engellemek yerine, size yardım etmek için var.\n\n#### Saflık\nGenellikle fonksiyonlarınız dış dünyada bir şeyi değiştirmeyecekler. Bu demek oluyor ki, bir değişkenin değerini değiştiremeyecekler, kullanıcıdan girdi alamayacaklar, ekrana yazı yazamayacaklar, veya bir füzeyi ateşleyemeyecekler. Diğer yandan, paralellik sağlamak çok kolay olacak. Haskell nerede yan etkilerin olduğunun ve nerede kodunuzun saf olduğunun ayrımını çok açık bir şekilde yapar. Ayrıca, programınız hakkında mantık yürütmek de çok daha kolay olur. Çoğu hata, kodunuzun saf kısmında engellecektir.\n\nDaha da ötesi, Haskell'de saf fonksiyonlar temel bir kural izlerler:\n> Bir fonksiyona aynı parametreleri vermek her zaman aynı değerleri döndürür.\n\n#### Tembellik\nTembellik, genelde alışılmadık bir dil tasarım tercihidir. Haskell'de varsayılan olarak her şey sadece ihtiyaç olduğunda hesaplanır / işlenir. Bunun sonuçlarından biri de sonsuz yapıları işlemek için çok mükemmel bir yol sunmasıdır.\n\nSon uyarı da Haskell kodunu nasıl okumanız gerektiğiyle ilgili. Benim için, bilimsel makaleleri okumak gibi. Bazı kısımları çok açık, ama bir formül gördünüzde odaklanın ve yavaşça okuyun. Ayrıca, Haskell öğrenirken, garip söz dizimsel detayları anlamamanız *gerçekten* önemli değil. Ama eğer `>>=`, `<$>`, `<-` v.b. herhangi bir garip sembol görürseniz, görmezden gelin ve kodun akışını takip edin.\n\n### 1.3.1. Fonksiyon tanımı\nŞu şekilde fonksiyon tanımlamaya alışmış olabilirsiniz:\n\nC'de:\n```c\nint f(int x, int y) {\n    return x*x + y*y;\n}\n```\n\nJavaScript'te:\n```javascript\nfunction f(x,y) {\n    return x*x + y*y;\n}\n```\n\nPython'da:\n```python\ndef f(x,y):\n    return x*x + y*y\n```\n\nRuby'de:\n```ruby\ndef f(x,y)\n    x*x + y*y\nend\n```\n\nScheme'de:\n```scheme\n(define (f x y)\n    (+ (* x x) (* y y)))\n```\n\nSon olarak, Haskell yolu da budur:\n```haskell\nf x y = x*x + y*y\n```\n\nTertemiz. Parantez yok, `def` yok.\n\nUnutmayın, Haskell fonksiyonları ve tipleri sıkça kullanır. Bu yüzden, onları tanımlamak oldukça kolaydır. Söz dizimi, özellikle öyle düşünülmüştür.\n\n### 1.3.2. Tip örneği\n\nZorunlu olmamasına rağmen, fonksiyonlar için tip bilgisi genellikle ayrıca girilir. Zorunlu değildir, çünkü derleyici sizin için çıkarım yapacak kadar akıllıdır. Yine de tipleri yazmak iyi bir fikirdir, çünkü kodun anlaşılmasına yardımcı olur.\n\nBakalım nasıl oluyormuş:\n\n```haskell\n-- Tipleri belirtmek icin :: isaretini kullaniyoruz\nf :: Int -> Int -> Int\nf x y = x*x + y*y\n\nmain = print (f 2 3)\n```\n\n```\n~ runhaskell 20_very_basic.lhs\n13\n```\n[01_basic/10_Introduction/20_very_basic.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/01_basic/10_Introduction/20_very_basic.lhs)\n\n***\n[01_basic/10_Introduction/21_very_basic.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/01_basic/10_Introduction/21_very_basic.lhs)\n\nŞimdi bunu deneyelim:\n\n```haskell\nf :: Int -> Int -> Int\nf x y = x*x + y*y\n\nmain = print (f 2.3 4.2)\n```\n\nŞu hatayı almış olmalısınız:\n\n```\n21_very_basic.lhs:6:23:\n    No instance for (Fractional Int)\n      arising from the literal `4.2'\n    Possible fix: add an instance declaration for (Fractional Int)\n    In the second argument of `f', namely `4.2'\n    In the first argument of `print', namely `(f 2.3 4.2)'\n    In the expression: print (f 2.3 4.2)\n```\nSorun şu: `4.2` bir tam sayı (Int) değil.\n\n[01_basic/10_Introduction/21_very_basic.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/01_basic/10_Introduction/21_very_basic.lhs)\n\n***\n\n[01_basic/10_Introduction/22_very_basic.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/01_basic/10_Introduction/22_very_basic.lhs)\n\nÇözümü de şu: `f` fonksiyonu için şimdilik bir tip belirtmeyelim ve Haskell'in tip çıkarımı yapmasına izin verelim.\n\n```haskell\nf x y = x*x + y*y\n\nmain = print (f 2.3 4.2)\n```\n\nÇalışıyor! Ne şanslıyız ki, her tip için yeni bir fonksiyon tanımlamak zorunda değiliz. Örneğin `C`'de, `int` için, `float` için, `long` için, `double` için vs. ayrı ayrı fonksiyon tanımlamak zorundayız.\n\nPeki hangi tipi belirtmeliydik? Haskell'in bizim için bulduğu tipi görmek için `ghci`'yi başlatın:\n\n```\n% ghci\nGHCi, version 7.0.4: http://www.haskell.org/ghc/  :? for help\nLoading package ghc-prim ... linking ... done.\nLoading package integer-gmp ... linking ... done.\nLoading package base ... linking ... done.\nLoading package ffi-1.0 ... linking ... done.\nPrelude> let f x y = x*x + y*y\nPrelude> :type f\nf :: Num a => a -> a -> a\n```\n\nHi? Bu garip tip de neyin nesi?\n\n```\nNum a => a -> a -> a\n```\n\nİlk önce, sağdaki `a -> a -> a` kısmına bakalım. Anlamak için kademeli olarak şu örnekleri inceleyelim:\n\n| Yazılı Tip   | Anlamı                                                                  |\n| ------------ | ----------------------------------------------------------------------- |\n| Int          | Int tipi                                                                |\n| Int -> Int   | Int'ten Int'e olan fonksiyon tipi                                       |\n| Float -> Int | Float'tan Int'e olan fonksiyon tipi                                     |\n| a -> Int     | herhangi bir tipten Int'e olan fonksiyon tipi                           |\n| a -> a       | herhangi bir a tipinden aynı a tipine olan fonksiyon tipi               |\n| a -> a -> a  | herhangi bir a tipinden iki argümanın aynı a tipine olan fonksiyon tipi |\n\n`a -> a -> a` tipinde, `a` harfine tip değişkeni diyoruz. *(type variable)*. Bu `f`'nin iki argümanı olduğu, ve girilen argümanlar ve fonksiyon sonucunun aynı tipten olduğu anlamına geliyor. Tip değişkeni `a`, başka bir sürü değer alabilir. Örneğin `Int`, `Integer`, `Float`...\n\nYani `C`'deki gibi zorunlu olarak bir fonksiyon için `int`, `long`, `float`, `double` vs. gibi tip belirtmek yerine, herhangi bir dinamik tip sistemli dil gibi sadece bir fonksiyon tanımlıyoruz.\n\nBuna bazen parametrik çokşekillilik *(parametric polymorphism)* de deniyor. Hayatta her istediğinizin olması gibi bir şey.\n\nGenellikle `a` herhangi bir tip olabilir, örneğin `String` veya `Int`, ama `Trees` gibi daha karışık tipler, başka fonksiyonlar da olabilir. Ama buradaki tipimiz `Num a =>` ile başlıyor.\n\n`Num` bir tip sınıfı. *(type class)*. Tip sınıfları tip grupları gibi düşünülebilir. `Num` sınıfı sadece sayı gibi davranan tipleri içerir. Daha doğrusu, `Num`, belli bir fonksiyon listesinin, özellikle `(+)` ve `(*)` fonksiyonlarının, etki ettiği sınıftır.\n\nTip sınıfları güçlü bir dil yapısıdır. Onlarla inanılmaz güçlü şeyler yapabiliriz. Buna daha sonra tekrar değineceğiz.\n\nSonuç olarak, `Num a => a -> a -> a` şu demek oluyor:\n\nDiyelim ki `a`, `Num` tip sınıfına ait bir tip. Bu da `a` tipinden `a -> a` tipine bir fonksiyon.\n\nEvet, garip. Aslında Haskell'de hiçbir fonksiyonun gerçekten iki argümanı yoktur. Onun yerine, her fonksiyonun sadece bir argümanı vardır. Ama hatırlamalıyız ki iki argüman almakla, bir argüman alıp ikinci argümanı bir parametre olarak alan bir fonksiyon döndürmek denk şeylerdir.\n\nDaha açık olmak gerekirse, `f 3 4`, `(f 3) 4`'e denktir. `f 3`'un de bir fonksiyon olduğuna dikkat edin:\n\n```haskell\nf :: Num a => a -> a -> a\n\ng :: Num a => a -> a\ng = f 3\n\ng y ⇔ 3*3 + y*y\n```\n\nFonksiyonlar için bir notasyon daha var. Lambda notasyonu isimsiz fonksiyonlar yaratmamıza olanak sağlar. Bunlara anonim fonksiyonlar diyoruz. Aynı şeyi lambda notasyonuyla şöyle de yazabilirdik:\n\n```haskell\ng = \\y -> 3*3 + y*y\n```\n\nBurada `\\` kullanılıyor, çünkü `λ` (lambda) harfine benziyor, ve aynı zamanda ASCII dizisine dahil.\n\nEğer fonksiyonel programlamaya alışık değilseniz beyniniz yanmaya başlamış olmalı. Artık gerçek bir uygulama yazma zamanı.\n\n[01_basic/10_Introduction/22_very_basic.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/01_basic/10_Introduction/22_very_basic.lhs)\n\n***\n\n[01_basic/10_Introduction/23_very_basic.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/01_basic/10_Introduction/23_very_basic.lhs)\n\nAma ondan önce, tip sisteminin beklediğimiz gibi çalıştığını doğrulayalım:\n\n```haskell\nf :: Num a => a -> a -> a\nf x y = x*x + y*y\n\nmain = print (f 3 2.4)\n```\n\nÇalışıyor, çünkü `3` hem `Float` gibi kesirli *(Fractional)* sayılar için, hem de `Integer` (tam sayı tipi) için geçerli bir gösterim. `2.4` kesirli bir sayı olduğu için `3` de kesirli bir sayı olarak yorumlanıyor.\n\n[01_basic/10_Introduction/23_very_basic.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/01_basic/10_Introduction/23_very_basic.lhs)\n\n***\n\n[01_basic/10_Introduction/24_very_basic.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/01_basic/10_Introduction/24_very_basic.lhs)\n\nEğer fonksiyonumuzu farklı tiplerle çalışmaya zorlarsak, hata verecektir:\n\n```haskell\nf :: Num a => a -> a -> a\nf x y = x*x + y*y\n\nx :: Int\nx = 3\ny :: Float\ny = 2.4\nmain = print (f x y) -- calismayacak, cunku tip x ≠ tip y\n```\n\nDerleyici hata veriyor. İki parametre de aynı tipten olmak zorunda.\n\nEğer bunun kötü bir fikir olduğunu ve derleyicinin sizin için bir tipten diğerine dönüşümü yapması gerektiğini düşünüyorsanız, bu müthiş (ve komik) videoyu mutlaka izlemelisiniz: [WAT](https://www.destroyallsoftware.com/talks/wat)\n\n[01_basic/10_Introduction/24_very_basic.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/01_basic/10_Introduction/24_very_basic.lhs)\n\n\n# 2. Temel Haskell\n\n![Essential](http://yannesposito.com/Scratch/img/blog/Haskell-the-Hard-Way/kandinsky_gugg.jpg)\n\nBu kısma yalnızca göz gezdirmenizi tavsiye ediyorum. Her zaman yararlanacağınız bir kaynak gibi düşünün. Haskell'in birçok özelliği vardır. Burada da pek çoğu eksik. Eğer notasyon garip gelirse tekrar buraya dönün.\n\nİki ifadenin denk olduğunu belirtmek için `⇔` işaretini kullanıyorum. Bu sahte bir notasyon, `⇔` Haskell'de mevcut değil. Aynı şekilde, bir ifadenin hesaplanan değerinin ne olduğunu belirtmek için de `⇒` işaretini kullanacağım.\n\n## 2.1. Notasyon\n\n### Aritmetik\n\n``` haskell\n3 + 2 * 6 / 3 ⇔ 3 + ((2*6)/3)\n```\n\n### Mantıksal\n\n```haskell\nTrue || False ⇒ True\nTrue && False ⇒ False\nTrue == False ⇒ False\nTrue /= False ⇒ True  (/=) esit degildir operatorudur\n```\n\n### Üslü Sayılar\n\n```haskell\nx^n     herhangi bir n integral tipi icin (Int veya Integer olarak anlayin)\nx**y    herhangi bir y sayi tipi icin (ornegin Float)\n```\n\n`Integer`'ın bilgisayarınızın kapasitesi dışında bir sınırı yoktur.\n\n```\n4^103\n102844034832575377634685573909834406561420991602098741459288064\n```\n\nEvet! Ayrıca rasyonel sayılar da var! Ama önce `Data.Ratio` modülünü içeri aktarmanız gerekiyor:\n\n```\n$ ghci\n....\nPrelude> :m Data.Ratio\nData.Ratio> (11 % 15) * (5 % 3)\n11 % 9\n```\n\n### Listeler\n\n```\n[]                      ⇔ bos liste\n[1,2,3]                 ⇔ integral listesi\n[\"foo\",\"bar\",\"baz\"]     ⇔ String listesi\n1:[2,3]                 ⇔ [1,2,3], (:) bir elemani one ekleme\n1:2:[]                  ⇔ [1,2]\n[1,2] ++ [3,4]          ⇔ [1,2,3,4], (++) birlestirme\n[1,2,3] ++ [\"foo\"]      ⇔ HATA String ≠ Integral\n[1..4]                  ⇔ [1,2,3,4]\n[1,3..10]               ⇔ [1,3,5,7,9]\n[2,3,5,7,11..100]       ⇔ HATA! O kadar da akilli degilim!\n[10,9..1]               ⇔ [10,9,8,7,6,5,4,3,2,1]\n```\n\n### Karakter Dizileri\n\nHaskell'de `String` tipi, `Char` tipinden oluşmuş listeye denktir.\n\n```\n'a' :: Char\n\"a\" :: [Char]\n\"\"    ⇔ []\n\"ab\"  ⇔ ['a','b'] ⇔  'a':\"b\" ⇔ 'a':['b'] ⇔ 'a':'b':[]\n\"abc\" ⇔ \"ab\"++\"c\"\n```\n\n> Dikkat: Gerçek kodda, yazıyı temsil etmek için `Char` listesi kullanmamalısınız. Genel olarak `Data.Text` kullanmalısınız. Eğer ASCİİ karakter akımını *(stream)* temsil etmek istiyorsanız, onun için de `Data.ByteString` kullanmalısınız.\n\n### Demetler *(Tuple)*\n\nBir ikili demetin tipi `(a,b)`'dir. Demetlerdeki elemanlar farklı tipte olabilirler.\n\n```haskell\n-- Tum bu demetler gecerlidir\n(2,\"foo\")\n(3,'a',[2,3])\n((2,\"a\"),\"c\",3)\n\nfst (x,y)       ⇒  x\nsnd (x,y)       ⇒  y\n\nfst (x,y,z)     ⇒  HATA: fst :: (a,b) -> a\nsnd (x,y,z)     ⇒  HATA: snd :: (a,b) -> b\n```\n\n### Parantezlerle Başa Çıkmak\n\nBazı parantezlerden kurtulmak için `($)` ve `(.)` fonksiyonlarını kullanabilirsiniz.\n\n```haskell\n-- Aslinda:\nf g h x         ⇔  (((f g) h) x)\n\n-- $ isareti kendisinden ifadenin sonuna\n-- kadar olan parantezin yerine gecer\nf g $ h x       ⇔  f g (h x) ⇔ (f g) (h x)\nf $ g h x       ⇔  f (g h x) ⇔ f ((g h) x)\nf $ g $ h x     ⇔  f (g (h x))\n\n-- (.) kompozisyon fonksiyonu\n(f . g) x       ⇔  f (g x)\n(f . g . h) x   ⇔  f (g (h x))\n```\n\n***\n\n[01_basic/20_Essential_Haskell/10a_Functions.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/01_basic/20_Essential_Haskell/10a_Functions.lhs)\n\n## 2.2. Fonksiyonlar için Faydalı Notasyonlar\n\nHatırlatma:\n\n```haskell\nx :: Int            ⇔ x Int tipinde herhangi bir deger alabilir\nx :: a              ⇔ x herhangi bir tip olabilir\nx :: Num a => a     ⇔ x Num tip sinifina dahil olan\n                         herhangi bir a tipi olabilir\nf :: a -> b         ⇔ f a'dan b'ye bir fonksiyondur\nf :: a -> b -> c    ⇔ f a'dan (b→c)'ye bir fonksiyondur\nf :: (a -> b) -> c  ⇔ f (a→b)'den c'ye bir fonksiyondur\n```\n\nHatırlayın ki bir fonksiyonu tanımlamadan önce tipini belirtmek zorunlu değil. Haskell genelde tip çıkarımını sizin için kendisi yapar. Ama genelde tipleri belirtmek iyi uygulama olarak görülür.\n\n#### Orta notasyon\n\n```haskell\nsquare :: Num a => a -> a\nsquare x = x^2\n```\n\n`^` işaretinin orta notasyon kullandığına dikkat edin. Her orta notasyon için bir başta notasyon vardır. Sadece parantez içine koymak durumundasınız.\n\n```haskell\nsquare' x = (^) x 2\n\nsquare'' x = (^2) x\n```\n\nSoldaki ve sağdaki `x`'leri silebiliriz. Buna η (eta) sadeleştirmesi deniyor.\n\n```haskell\nsquare''' = (^2)\n```\n\nDeğişken isimlerinde `'` kullanabildiğimize dikkat edin.\n\n> `square` ⇔ `square'` ⇔ `square''` ⇔ `square'''`\n\n### Testler\n\nMutlak değer fonksiyonu yazalım:\n\n```haskell\nabsolute :: (Ord a, Num a) => a -> a\nabsolute x = ıf x >= 0 then x else -x\n```\n\nDikkat edin ki Haskell'deki `if .. then .. else` notasyonu, C'deki `¤?¤:¤` operatörüne çokça benziyor. `else` kısmını unutmanız mümkün değil.\n\nDenk başka bir versiyonu:\n\n```haskell\nabsolute' x\n    | x >= 0 = x\n    | otherwise = -x\n```\n\n> Haskell'de paragraf başı / boşluklar önemlidir. Python'daki gibi, kötü boşluklar kodunuzu bozabilir.\n\n[01_basic/20_Essential_Haskell/10a_Functions.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/01_basic/20_Essential_Haskell/10a_Functions.lhs)\n\n# 3. Zor Kısım\n\nZor kısım şimdi başlıyor.\n\n## 3.1. Fonksiyonel Stil\n\n![Functional](http://yannesposito.com/Scratch/img/blog/Haskell-the-Hard-Way/hr_giger_biomechanicallandscape_500.jpg)\n\nBu bölümde, Haskell'in etkileyici yeniden yapılandırma *(refactoring)* yeteneklerini göreceğiz. Bir problem seçip önce standart imperatif yolla çözeceğiz. Daha sonra kodun evrimini göreceğiz, son hali çok daha zarif ve kolay anlaşılabilir olacak.\n\nAşağıdaki problemi çözelim:\n\n> Verilen bir tam sayı listesindeki çift sayıların toplamını alın.\n> Örnek: `[1,2,3,4,5] ⇒ 2 + 4 ⇒ 6`\n\nFonksiyonel ve imperatif yaklaşımların arasındaki farkı göstermek için, imperatif çözümü göstererek başlayacağım: (JavaScript'te)\n\n```javascript\nfunction evenSum(list) {\n    var result = 0;\n    for (var i=0; i< list.length ; i++) {\n        if (list[i] % 2 ==0) {\n            result += list[i];\n        }\n    }\n    return result;\n}\n```\n\nHaskell'de, farklı olarak, değişkenler veya `for` döngüleri yoktur. Döngüler olmaksızın aynı sonucu elde etmenin bir yolu özyinelemedir. *(recursion)*\n\n> Dikkat: Özyineleme imperatif dillerde genellikle yavaş olarak algılanır. Fonksiyonel programlamada genellikle durum bu değildir. Çoğu zaman Haskell özyinelemeli fonksiyonları verimli şekilde işler.\n\nİşte özyinelemeli fonksiyonun C versiyonu. Basitlik için tam sayı listesinin ilk `0` değeri ile bittiğini varsaydığıma dikkat edin.\n\n```c\nint evenSum(int *list) {\n    return accumSum(0,list);\n}\n\nint accumSum(int n, int *list) {\n    int x;\n    int *xs;\n    if (*list == 0) { // eger liste bossa\n        return n;\n    } else {\n        x = list[0]; // x listenin ilk elemani olsun\n        xs = list+1; // xs listenin ilk elemani haric geri kalani olsun\n        if ( 0 == (x%2) ) { // eger x ciftse\n            return accumSum(n+x, xs);\n        } else {\n            return accumSum(n, xs);\n        }\n    }\n}\n```\n\nBu kodu aklınızda tutun. Şimdi onu Haskell'e çevireceğiz. Ama ilk önce, size burada kullanacağımız üç basit ama kullanışlı fonksiyonu tanıtmam gerekiyor:\n\n```haskell\neven :: Integral a => a -> Bool\nhead :: [a] -> a\ntail :: [a] -> [a]\n```\n\n`even` bir sayının çift olduğunu doğrular.\n\n```haskell\neven :: Integral a => a -> Bool\neven 3  ⇒ False\neven 2  ⇒ True\n```\n\n`head` bir listenin ilk elemanını döndürür.\n\n```haskell\nhead :: [a] -> a\nhead [1,2,3] ⇒ 1\nhead []      ⇒ HATA\n```\n\n`tail` bir listenin ilk elemanı hariç tüm elemanlarını döndürür.\n\n```haskell\ntail :: [a] -> [a]\ntail [1,2,3] ⇒ [2,3]\ntail [3]     ⇒ []\ntail []      ⇒ HATA\n```\n\nGörebileceğiniz üzere, herhangi bir boş olmayan `l` listesi için, `l ⇔ (head l):(tail l)`\n\n***\n\n[02_Hard_Part/11_Functions.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/11_Functions.lhs)\n\n\nİlk Haskell çözümümüz. `evenSum` fonksiyonu bir listedeki tüm çift sayıların toplamını döndürür.\n\n```haskell\n-- Versiyon 1\nevenSum :: [Integer] -> Integer\n\nevenSum l = accumSum 0 l\n\naccumSum n l = if l == []\n                  then n\n                  else let x = head l\n                           xs = tail l\n                       in if even x\n                              then accumSum (n+x) xs\n                              else accumSum n xs\n```\n\nFonksiyonu denemek için `ghci`'ı kullanabilirsiniz.\n\n```\n% ghci\nGHCi, version 7.0.3: http://www.haskell.org/ghc/  :? for help\nLoading package ghc-prim ... linking ... done.\nLoading package integer-gmp ... linking ... done.\nLoading package base ... linking ... done.\nPrelude> :load 11_Functions.lhs\n[1 of 1] Compiling Main             ( 11_Functions.lhs, interpreted )\nOk, modules loaded: Main.\n*Main> evenSum [1..5]\n6\n```\n\nBurada çalıştırılma örneğini görebilirsiniz: [^fn-2]\n\n```\n*Main> evenSum [1..5]\naccumSum 0 [1,2,3,4,5]\n1 is odd\naccumSum 0 [2,3,4,5]\n2 is even\naccumSum (0+2) [3,4,5]\n3 is odd\naccumSum (0+2) [4,5]\n4 is even\naccumSum (0+2+4) [5]\n5 is odd\naccumSum (0+2+4) []\nl == []\n0+2+4\n0+6\n6\n```\n\nİmperatif bir dilden geliyorsanız her şey doğru gözüküyor olmalı. Aslında burada pek çok şey geliştirilebilir. Öncelikle, tipi genelleyebiliriz.\n\n```haskell\nevenSum :: Integral a => [a] -> a\n```\n\n[02_Hard_Part/11_Functions.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/11_Functions.lhs)\n\n***\n\n[02_Hard_Part/12_Functions.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/12_Functions.lhs)\n\nDaha sonra, `where` veya `let` kullanarak alt fonksiyonlar tanımlayabiliriz. Bu şekilde `accumSum` fonksiyonu modülümüzün üst seviye isim uzayını *(namespace)* kirletmemiş olur.\n\n```haskell\n-- Versiyon 2\nevenSum :: Integral a => [a] -> a\n\nevenSum l = accumSum 0 l\n    where accumSum n l =\n            if l == []\n                then n\n                else let x = head l\n                         xs = tail l\n                     in if even x\n                            then accumSum (n+x) xs\n                            else accumSum n xs\n```\n\n[02_Hard_Part/12_Functions.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/12_Functions.lhs)\n\n***\n\n[02_Hard_Part/13_Functions.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/13_Functions.lhs)\n\nSonra, örüntülü eşleme *(pattern matching)* kullanabiliriz.\n\n```haskell\n-- Versiyon 3\nevenSum l = accumSum 0 l\n    where\n        accumSum n [] = n\n        accumSum n (x:xs) =\n             if even x\n                then accumSum (n+x) xs\n                else accumSum n xs\n```\n\nPeki örüntülü eşleme nedir? Genel parametre isimleri yerine değerlerin kendisini kullanın. [^fn-3]\n\n`foo l = if l == [] then <x> else <y>` demek yerine, basitçe şöyle diyorsunuz:\n\n```haskell\nfoo [] =  <x>\nfoo l  =  <y>\n```\n\nAma örüntülü eşleme bundan daha fazlası. Aynı zamanda karmaşık bir değerin iç verişini takip etmenin bir yolu. Şu kodun yerine:\n\n```haskell\nfoo l =  let x  = head l\n             xs = tail l\n         in if even x\n             then foo (n+x) xs\n             else foo n xs\n```\n\nşunu yazabiliriz:\n\n```haskell\nfoo (x:xs) = if even x\n                 then foo (n+x) xs\n                 else foo n xs\n```\n\nBu çok kullanışlı bir özellik. Aynı zamanda kodumuzu daha kısa ve okunaklı kılıyor.\n\n[02_Hard_Part/13_Functions.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/13_Functions.lhs)\n\n***\n\n[02_Hard_Part/14_Functions.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/14_Functions.lhs)\n\nHaskell'de η sadeleştirmesi yaparak fonksiyonları basitleştirebilirsiniz. Örneğin, şunu yazmak yerine:\n\n```\nf x = (some expression) x\n```\n\nbasitçe şunu yazabilirsiniz:\n\n```\nf = some expression\n```\n\nBu metodu `l`'yi kaldirmak icin kullanalim:\n\n```haskell\n-- Version 4\nevenSum :: Integral a => [a] -> a\n\nevenSum = accumSum 0\n    where\n        accumSum n [] = n\n        accumSum n (x:xs) =\n             if even x\n                then accumSum (n+x) xs\n                else accumSum n xs\n```\n\n[02_Hard_Part/14_Functions.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/14_Functions.lhs)\n\n***\n\n[02_Hard_Part/15_Functions.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/15_Functions.lhs)\n\n### 3.1.1. Üst Derece Fonksiyonlar\n\n![Higher Order](http://yannesposito.com/Scratch/img/blog/Haskell-the-Hard-Way/escher_polygon.png)\n\nHer şeyi daha da iyi yapmak için, üst derece fonksiyonları kullanmalıyız. Peki bu canavarlar nelerdir? Üst derece fonksiyonlarlar, başka fonksiyonları parametre olarak alan fonksiyonlardır.\n\nBazı örnekleri şöyledir:\n\n```haskell\nfilter :: (a -> Bool) -> [a] -> [a]\nmap :: (a -> b) -> [a] -> [b]\nfoldl :: (a -> b -> a) -> a -> [b] -> a\n```\n\nUfak adımlarla ilerleyelim.\n\n```haskell\n-- Version 5\nevenSum l = mysum 0 (filter even l)\n    where\n      mysum n [] = n\n      mysum n (x:xs) = mysum (n+x) xs\n```\n\nki burada,\n\n```haskell\nfilter even [1..10] ⇔  [2,4,6,8,10]\n```\n\n`filter` fonksiyonu `a -> Bool` tipinde bir fonksiyonu  ve `[a]` tipinde bir listeyi argüman olarak alır. Bu listeden sadece bu fonksiyon çalıştırıldığında `True` dönen elemanları dondurur.\n\nSonraki adımımız, döngüye benzer bir şeyi başarmak. `foldl` fonksiyonunu listede adım adım ilerlerken yanda bir değer biriktirmek için kullanacağız. `foldl` fonksiyonu aslında şu kalıbı alıp:\n\n```haskell\nmyfunc list = foo initialValue list\n    foo accumulated []     = accumulated\n    foo tmpValue    (x:xs) = foo (bar tmpValue x) xs\n```\n\nŞu hale çevirir:\n\n```haskell\nmyfunc list = foldl bar initialValue list\n```\n\nEğer gerçekten bu sihirli şeyin nasıl çalıştığını görmek istiyorsanız, `foldl`'in tanımı şöyledir:\n\n```haskell\nfoldl f z [] = z\nfoldl f z (x:xs) = foldl f (f z x) xs\n```\n\n```haskell\nfoldl f z [x1,...xn]\n⇔  f (... (f (f z x1) x2) ...) xn\n```\n\nAma Haskell tembel olduğu için `(f z x)`'in değerini hesaplamaz ve sadece yığının üstüne koyar. Bu yüzden genelde `foldl` yerine `foldl'` kullanırız; `foldl'`, `foldl` fonksiyonunun tembel olmayan versiyonudur. Eğer tembel ve tembel olmayan kavramlarını anlamıyorsanız, tasalanmayın, kodu `foldl` ve `foldl'` aynı şeylermiş gibi takip edin.\n\nŞimdi `evenSum` fonksiyonumuzun yeni hali şöyle oldu:\n\n```haskell\n-- Versiyon 6\n-- foldl' dogrudan erisilebilir\n-- erismek icin once Data.List modulunu iceri almamiz gerekiyor\nimport Data.List\nevenSum l = foldl' mysum 0 (filter even l)\n  where mysum acc value = acc + value\n```\n\nDoğrudan lambda notasyonu kullanarak daha da basitleştirebiliriz. Böylece `mysum` isminde geçici bir fonksiyon yaratmak zorunda kalmayız.\n\n```haskell\n-- Versiyon 7\n-- Genelde sadece ihtiyac duydugunuz fonksiyonlari\n-- iceri almak daha iyi bir yontemdir\nimport Data.List (foldl')\nevenSum l = foldl' (\\x y -> x+y) 0 (filter even l)\n```\n\nVe tabii ki, dikkat edelim ki:\n\n```haskell\n(\\x y -> x+y) ⇔ (+)\n```\n\n[02_Hard_Part/15_Functions.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/15_Functions.lhs)\n\n***\n\n[02_Hard_Part/16_Functions.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/16_Functions.lhs)\n\nSon olarak,\n\n```haskell\n-- Versiyon 8\nimport Data.List (foldl')\nevenSum :: Integral a => [a] -> a\nevenSum l = foldl' (+) 0 (filter even l)\n```\n\n`foldl'` anlaması kolay bir fonksiyon sayılmaz. Eğer alışık değilseniz, üzerinde biraz çalışmalısınız.\n\nBurada ne olduğunu anlamanız için adım adım neler olduğuna bakalım:\n\n```haskell\n  evenSum [1,2,3,4]\n⇒ foldl' (+) 0 (filter even [1,2,3,4])\n⇒ foldl' (+) 0 [2,4]\n⇒ foldl' (+) (0+2) [4]\n⇒ foldl' (+) 2 [4]\n⇒ foldl' (+) (2+4) []\n⇒ foldl' (+) 6 []\n⇒ 6\n```\n\nBaşka bir kullanışlı üst derece fonksiyon da `(.)` fonksiyonudur. `(.)` fonksiyonu matematiksel bileşimi *(composition)* ifade eder.\n\n```haskell\n(f . g . h) x ⇔  f ( g (h x))\n```\n\nBu operatörden fonksiyonumuzda η sadeleştirmesi yapmak için faydanalabiliriz:\n\n```haskell\n-- Versiyon 9\nimport Data.List (foldl')\nevenSum :: Integral a => [a] -> a\nevenSum = (foldl' (+) 0) . (filter even)\n```\n\nAyrıca, bazı kısımları daha iyi açıklamak için yeniden isimlendirebiliriz:\n\n```haskell\n-- Versiyon 10\nimport Data.List (foldl')\nsum' :: (Num a) => [a] -> a\nsum' = foldl' (+) 0\nevenSum :: Integral a => [a] -> a\nevenSum = sum' . (filter even)\n```\n\nŞimdi bu fonksiyonel ifadelerle kodumuzun ne yöne doğru gittiğini tartışalım. Üst derece fonksiyonları kullanmak bize ne kazandırdı?\n\nİlk önce, düşünebilirsiniz ki temel fark kısalık. Ama aslında, fark daha çok doğru düşünmeyle ilgili. Fonksiyonumuzu biraz değiştirmek istediğimizi varsayalım, örneğin bir listedeki tüm elemanların karesini alıp o çift kareleri toplamak istediğimizi.\n\n```\n[1,2,3,4] ▷ [1,4,9,16] ▷ [4,16] ▷ 20\n```\n\nVersiyon 10'u değiştirmek oldukça kolay:\n\n```haskell\nsquareEvenSum = sum' . (filter even) . (map (^2))\nsquareEvenSum' = evenSum . (map (^2))\nsquareEvenSum'' = sum' . (map (^2)) . (filter even)\n```\n\nSadece bir tane daha transformasyon fonksiyonu ekledik, o kadar. [^fn-4]\n\n```haskell\nmap (^2) [1,2,3,4] ⇔ [1,4,9,16]\n```\n\n`map` fonksiyonu basitçe bir listenin tüm elemanlarını etkiler.\n\nFonksiyon tanımının *içinde* herhangi bir şey değiştirmek zorunda kalmadık. Ama ek olarak, fonksiyonunuz hakkında daha matematiksel olarak akıl yürütebiliyorsunuz. Ayrıca fonksiyonunuzu diğerleriyle değişmeli de kullanabiliyorsunuz. Yani, yeni fonksiyonunuzu kullanarak `compose`, `map`, `fold`, `filter` işlemlerini yapabilirsiniz.\n\nVersiyon 1'i değiştirmek de okura bir alıştırma olarak kalsın. ☺.\n\nEğer genellemenin sonuna geldiğimizi düşünüyorsanız, oldukça yanılıyorsunuz. Örneğin, bunu sadece liste değil başka herhangi bir özyinelemeli türde kullanmanın yolları var. Eğer nasıl olduğunu bilmek istiyorsanız, size şu eğlenceli makaleyi okumanızı öneriyorum: [Muz, Mercek, Zarf ve Dikenli Tellerle Fonksiyonel Programlama - Meijer, Fokkinga ve Paterson.](http://eprints.eemcs.utwente.nl/7281/01/db-utwente-40501F46.pdf)\n\nBu örnek size saf fonksiyonel programlamanın ne kadar güzel olduğunu göstermeli. Ne yazık ki, saf fonksiyonel programlama her kullanıma tam uygun değil. Ya da en azından öyle bir programlama dili henüz mevcut değil.\n\nHaskell'in büyük güçlerinden biri de alana özel dil *(domain specific language)* yaratma yeteneğidir, böylece programlama paradigmasını değiştirebilirsiniz.\n\nAslında, Haskell imperatif stilde program yazmak istediğinizde de güzeldir. İlk Haskell öğrenmeye başladığımda bunu anlamak oldukça zor olmuştu. Genelde herkes fonksiyonel yaklaşımın üstünlüğünü anlatmaya çalışır. Daha sonra Haskell'le imperatif stil kullanmaya başlayınca, nasıl ve ne zaman öyle olacağını anlamak zor olabiliyor.\n\nBu Haskell süper gücüyle ilgili konuşmadan önce, Haskell'in başka bir temel yönünden bahsetmeliyiz: Tipler.\n\n[02_Hard_Part/16_Functions.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/16_Functions.lhs)\n\n## 3.2. Tipler\n\n![Types](http://yannesposito.com/Scratch/img/blog/Haskell-the-Hard-Way/salvador-dali-the-madonna-of-port-lligat.jpg)\n\n> TL, DR (Çok uzundu okumadım):\n> * `type Ad = BaskaTip` sadece bir takma addir ve derleyici `Ad` ve `BaskaTip` arasında bir fark gözetmez.\n> * `data Ad = AdYapısı BaskaTip` yapısında fark vardır.\n> * `data` anahtar kelimesi özyinelemeli yapılar yaratabilir.\n> * `deriving` sihirlidir ve sizin için fonksiyonlar yaratır.\n\nHaskell'de tipler güçlü ve statiktir.\n\nPeki bu neden önemli? Çünkü bu, hatalardan kaçınmanıza *yüksek derecede* yardımcı olur. Haskell'de hataların çoğu henüz derleme aşamasında yakalanır. Bunun asıl sebebi de tip çıkarımının derleme sırasında yapılmasıdır. Örneğin tip çıkarımı nerede yanlış parametreyi yanlış yerde kullandığınızı yakalar.\n\n### 3.2.1. Tip Çıkarımı\n\nStatik tip sistemi hızlı çalıştırma için genelde önemlidir. Ama çoğu statik tip sistemli diller kavramları genellemede kötüdür. Haskell'in kurtarıcı lütfü, tipleri kendi kendine *çıkarım* yaparak bulabilmesidir.\n\nBasit bir örnekle başlayalım, Haskell'deki `square` fonksiyonu:\n\n```haskell\nsquare x = x * x\n```\n\n`square` fonksiyonu Haskell'deki herhangi bir sayısal değerin karesini alabilir. `square` fonksiyonuna parametre olarak `Int`, `Integer`, `Float`, `Fractional`, hatta `Complex` tipinde veri bile verebilirsiniz. Örnekle kanıtlayalım:\n\n```\n% ghci\nGHCi, version 7.0.4:\n...\nPrelude> let square x = x*x\nPrelude> square 2\n4\nPrelude> square 2.1\n4.41\nPrelude> -- load the Data.Complex module\nPrelude> :m Data.Complex\nPrelude Data.Complex> square (2 :+ 1)\n3.0 :+ 4.0\n```\n\n`x :+ y` kompleks sayıların gösteriminde kullanılır. (x + iy)\n\nŞimdi C'deki gerekli kod miktarıyla karşılaştıralım:\n\n```c\nint     int_square(int x) { return x*x; }\n\nfloat   float_square(float x) {return x*x; }\n\ncomplex complex_square (complex z) {\n    complex tmp;\n    tmp.real = z.real * z.real - z.img * z.img;\n    tmp.img = 2 * z.img * z.real;\n}\n\ncomplex x,y;\ny = complex_square(x);\n```\n\nC'de her tip için yeni bir fonksiyon yazmanız gerekiyor. Bunu aşmanın tek yolu ön-işlemciyi kullanarak üst-programlama hilelerine başvurmak. C++'ta daha iyi bir yol var, C++ şablonları:\n\n```cpp\n#include <iostream>\n#include <complex>\nusing namespace std;\n\ntemplate<typename T>\nT square(T x)\n{\n    return x*x;\n}\n\nint main() {\n    // int\n    int sqr_of_five = square(5);\n    cout << sqr_of_five << endl;\n    // double\n    cout << (double)square(5.3) << endl;\n    // complex\n    cout << square( complex<double>(5,3) )\n         << endl;\n    return 0;\n}\n```\n\nC++ bu yönden C'den çok daha iyi iş çıkartıyor. Ama daha karmaşık fonksiyonlar için söz dizimini takip etmek biraz daha zor olabilir: örnek için [bu makaleye](http://bartoszmilewski.com/2009/10/21/what-does-haskell-have-to-do-with-c/) bakabilirsiniz.\n\nC++'ta bir fonksiyonun farklı tiplerle çalışması için ayrıca belirtmelisiniz. Haskell'de durum tam tersi. Fonksiyon varsayılan olarak olabildiğince genel tanımlanır.\n\nTip çıkarımı Haskell'de dinamik tip sistemli dillerin yarattığı özgürlük hissini yaratır. Ama dinamik tip sistemli dillerden farklı olarak çoğu hata çalışma zamanından önce yakalanır. Genelde Haskell kodu\n> derleniyorsa, mutlaka kastettiğiniz şeyi yapıyordur.\n\n***\n\n[02_Hard_Part/21_Types.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/21_Types.lhs)\n\n### 3.2.2. Tip Oluşturma\n\nKendi tiplerinizi oluşturabilirsiniz. İlk önce takma adlarla, yani tip eşanlamlılarıyla başlayalım.\n\n```haskell\ntype Name   = String\ntype Color  = String\n\nshowInfos :: Name ->  Color -> String\nshowInfos name color =  \"Isim: \" ++ name\n                        ++ \", Renk: \" ++ color\nname :: Name\nname = \"Ahmet\"\ncolor :: Color\ncolor = \"Mavi\"\nmain = putStrLn $ showInfos name color\n```\n\n[02_Hard_Part/21_Types.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/21_Types.lhs)\n\n***\n\n[02_Hard_Part/22_Types.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/22_Types.lhs)\n\nAncak bu çok fazla koruma yaratmıyor. `showInfos` fonksiyonuna verdiğiniz parametrelerin yerini değiştirip çalıştırmayı deneyin:\n```\nputStrLn $ showInfos color name\n```\n\nDerlenecek ve çalışacak. Aslında, `Name`, `Color` ve `String` tiplerini birbiriyle değiştirebilirsiniz, bir fark yaratmayacak. Derleyici hepsine aynıymış gibi muamele edecek.\n\nDiğer bir yöntem de `data` anahtar kelimesini kullanarak kendi tiplerinizi yaratmak.\n\n```haskell\ndata Name   = NameConstr String --NameConstr : isim yapicisi\ndata Color  = ColorConstr String --ColorConstr : renk yapicisi\n\nshowInfos :: Name ->  Color -> String\nshowInfos (NameConstr name) (ColorConstr color) =\n      \"Name: \" ++ name ++ \", Color: \" ++ color\n\nname  = NameConstr \"Ahmet\"\ncolor = ColorConstr \"Mavi\"\nmain = putStrLn $ showInfos name color\n```\n\nAma şimdi `showInfos` için parametrelerin yerlerini değiştirirseniz, derleyici hata verecek! Yani bu bir daha yapmayacağınız muhtemel bir hata, ve kaçınmak için tek yapmanız gereken biraz daha uzun yazmak.\n\nYapıcıların da birer fonksiyon olduğuna dikkat edin:\n\n```haskell\nNameConstr  :: String -> Name\nColorConstr :: String -> Color\n```\n\n`data` anahtar kelimesinin genel söz dizimi de şöyledir:\n\n```haskell\ndata TipAdi =   YapiciAdi  [tipler]\n                | YapiciAdi2 [tipler]\n                | ...\n```\n\nGenel kullanım tip adının ve yapıcı adının aynı olması yönündedir.\n\nÖrnek:\n\n```haskell\ndata Complex = Num a => Complex a a\n```\n\nKayıt *(record)* söz dizimini de kullanabilirsiniz:\n\n```haskell\ndata VeriTipiAdi = VeriYapicisi {\n                      alan_1 :: [alan_1 tipi]\n                    , alan_2 :: [alan_2 tipi]\n                    ...\n                    , alan_n :: [alan_n tipi] }\n```\n\nDaha da iyisi, alanlara erişim sağlayan fonksiyonlar sizin için oluşturuluyor. Ayrıca bu tipte bir veri oluştururken alanların sırasını da kullanabilirsiniz.\n\nÖrnek:\n\n```haskell\ndata Complex = Num a => Complex { real :: a, img :: a}\nc = Complex 1.0 2.0\nz = Complex { real = 3, img = 4 }\nreal c ⇒ 1.0\nimg z ⇒ 4\n```\n\n[02_Hard_Part/22_Types.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/22_Types.lhs)\n\n***\n\n[02_Hard_Part/23_Types.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/23_Types.lhs)\n\n### 3.2.3. Özyinelemeli Tipler *(Recursive types)*\n\nDaha önce özyinelemeli bir tiple karşılaşmıştık: listeler. Liste tipini -biraz daha uzun bir söz dizimiyle de olsa- kendimiz de oluşturabiliriz:\n\n```haskell\ndata List a = Empty | Cons a (List a)\n```\n\nEğer daha kolay bir söz dizimi yaratmak istiyorsanız, yapıcılar için iç notasyon *(infix)* tanımlayabilirsiniz.\n\n```haskell\ninfixr 5 :::\ndata List a = Nil | a ::: (List a)\n```\n\n`infixr`'dan sonraki sayı önceliği belirtiyor.\n\nEğer bu veri tipini ekrana yazdırmak (`Show`), karakter dizisinden çevirmek (`Read`), eşitliğini test etmek (`Eq`) ve karşılaştırmak (`Ord`) istiyorsanız, Haskell'e sizin için gerekli fonksiyonları oluşturmasını söyleyebilirsiniz.\n\n```haskell\ninfixr 5 :::\ndata List a = Nil | a ::: (List a)\n              deriving (Show,Read,Eq,Ord)\n```\n\nVeri tipi tanımınıza `deriving (Show)`'u eklediğinizde, Haskell sizin için bir `show` fonksiyonu yaratır. (*(deriving)* İngilizce'de türeme demektir.) Yakında kendi `show` fonksiyonunuzu nasıl kullanabileceğinizi göreceğiz.\n\n```haskell\nconvertList [] = Nil\nconvertList (x:xs) = x ::: convertList xs\n\nmain = do\n      print (0 ::: 1 ::: Nil)\n      print (convertList [0,1])\n```\n\nBu şu çıktıyı verir:\n\n```\n0 ::: (1 ::: Nil)\n0 ::: (1 ::: Nil)\n```\n\n[02_Hard_Part/23_Types.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/23_Types.lhs)\n\n***\n\n[02_Hard_Part/30_Trees.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/30_Trees.lhs)\n\n### 3.2.4. Ağaçlar\n\n![Trees](http://yannesposito.com/Scratch/img/blog/Haskell-the-Hard-Way/magritte-l-arbre.jpg)\n\nBaşka bir standart örnek verelim: ikili ağaçlar.\n\n```haskell\nimport Data.List\n\ndata BinTree a = Empty\n                 | Node a (BinTree a) (BinTree a)\n                              deriving (Show)\n```\n\nŞimdi de bir listeyi sıralı bir ikili ağaca dönüştüren bir fonksiyon yazalım:\n\n```haskell\ntreeFromList :: (Ord a) => [a] -> BinTree a\ntreeFromList [] = Empty\ntreeFromList (x:xs) = Node x (treeFromList (filter (<x) xs))\n                             (treeFromList (filter (>x) xs))\n```\n\nFonksiyonun ne kadar okunaklı olduğunu görebiliyor musunuz? Düz Türkçe olarak yazarsak:\n* boş liste, boş ağaca çevrilir.\n* bir liste `(x:xs)`, bir ağaca çevrilir ki,\n    * kok `x`'tır.\n    * sol alt ağaç, `xs`'in `x`'ten kesin olarak küçük elemanlarından oluşturulur.\n    * sağ alt ağaç, `xs`'in `x`'ten kesin olarak büyük elemanlarından oluşturulur.\n\n```haskell\nmain = print $ treeFromList [7,2,4,8]\n```\n\nŞu sonucu alıyor olmalısınız:\n\n```haskell\nNode 7 (Node 2 Empty (Node 4 Empty Empty)) (Node 8 Empty Empty)\n```\n\nBu ağacımızın düzgün ama zor anlaşılır bir temsili notasyonu.\n\n[02_Hard_Part/30_Trees.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/30_Trees.lhs)\n\n***\n\n[02_Hard_Part/31_Trees.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/31_Trees.lhs)\n\nÖylesine, ağacımız için daha iyi bir gösterim kodu yazalım. Ben genel olarak ağaçları daha iyi göstermek için bir fonksiyon yazarken eğlendim, eğer bu kısmı takip etmeyi zor buluyorsanız atlayabilirsiniz, bir sorun olmaz.\n\nDeğiştirmemiz gereken bazı şeyler var. `BinTree` tipımizden `deriving (Show)` kısmını kaldırıyoruz. Ayrıca, BinTree tipimizi (`Eq` ve `Ord`)'un sınıflarından türetmek de eşitlik ve karşılaştırma testleri yapmamızı sağlayacaktır.\n\n```haskell\ndata BinTree a = Empty\n                 | Node a (BinTree a) (BinTree a)\n                  deriving (Eq,Ord)\n```\n\n`deriving (Show)` kısmı olmadan Haskell sizin için bir `show` metodu yaratmaz. Biz `show` metodu için kendi versiyonumuzu yazacağız. Bunu başarmak için, yeni yarattığımız `BinTree a`'nin `Show` tip sınıfının bir üyesi olduğunu belirtmemiz gerekiyor. Bunun için genel söz dizimi şöyle:\n\n```haskell\ninstance Show (BinTree a) where\n   show t = ... -- burada kendi fonksiyonunuzu tanimliyorsunuz\n```\n\nBenim bir ikili ağacı göstermek için yazdığım versiyon aşağıda. Karmaşıkmış gibi görünüyor ama endişelenmeyin. Daha garip nesneleri de göstermesi için bazı iyileştirmeler yaptım.\n\n```haskell\n-- BinTree'a nin Show tip sinifina uye oldugunu belirtin\ninstance (Show a) => Show (BinTree a) where\n  -- kokten once bir '<' ile baslayacagiz\n  -- satir basina da : koyacagiz\n  show t = \"< \" ++ replace '\\n' \"\\n: \" (treeshow \"\" t)\n    where\n    -- treeshow pref Tree\n    --   bu fonksiyon her satira pref ile baslayarak bir agaci gosterecek\n    -- Bos agaci gostermeyecek\n    treeshow pref Empty = \"\"\n    -- Yaprak\n    treeshow pref (Node x Empty Empty) =\n                  (pshow pref x)\n\n    -- Sag alt agac bos\n    treeshow pref (Node x left Empty) =\n                  (pshow pref x) ++ \"\\n\" ++\n                  (showSon pref \"`--\" \"   \" left)\n\n    -- Sol alt agac bos\n    treeshow pref (Node x Empty right) =\n                  (pshow pref x) ++ \"\\n\" ++\n                  (showSon pref \"`--\" \"   \" right)\n\n    -- Sol ve sag alt agaclari bos olmayan agac\n    treeshow pref (Node x left right) =\n                  (pshow pref x) ++ \"\\n\" ++\n                  (showSon pref \"|--\" \"|  \" left) ++ \"\\n\" ++\n                  (showSon pref \"`--\" \"   \" right)\n\n    -- Agaci guzel gostermek icin on ekler kullan\n    showSon pref before next t =\n                  pref ++ before ++ treeshow (pref ++ next) t\n\n    -- pshow \"\\n\"'i' \"\\n\"++pref ile degistiriyor\n    pshow pref x = replace '\\n' (\"\\n\"++pref) (show x)\n\n    -- bir karakteri diger karakter dizisi ile degistiriyor\n    replace c new string =\n      concatMap (change c new) string\n      where\n          change c new x\n              | x == c = new\n              | otherwise = x:[] -- \"x\"\n```\n\n`treeFromList` metodu tamamen aynı kalıyor.\n\nŞimdi, görelim nasıl oluyormuş:\n\n```haskell\nmain = do\n  putStrLn \"Tam sayi ikili agaci:\"\n  print $ treeFromList [7,2,4,8,1,3,6,21,12,23]\n```\n\n```\nTam sayi ikili agaci:\n< 7\n: |--2\n: |  |--1\n: |  `--4\n: |     |--3\n: |     `--6\n: `--8\n:    `--21\n:       |--12\n:       `--23\n```\n\nÇok daha iyi, değil mi? Ağacın kökü `<` karakteriyle başlayan satırda gösteriliyor. Takip eden her satır `:` işareti ile başlıyor. Ağacımızda başka tiplerde veri de kullanabilirdik.\n\n```haskell\n  putStrLn \"\\nKarakter dizisi ikili agaci:\"\n  print $ treeFromList [\"foo\",\"bar\",\"baz\",\"gor\",\"yog\"]\n```\n\n```\nKarakter dizisi ikili agaci:\n< \"foo\"\n: |--\"bar\"\n: |  `--\"baz\"\n: `--\"gor\"\n:    `--\"yog\"\n```\n\nAğaçların eşitliğini ve büyük/küçüklüğünü test edebildiğimiz için, ağaçlardan ağaç da yapabiliriz!\n\n```haskell\n  putStrLn \"\\nKarakter ikili agaclarinin ikili agaci:\"\n  print ( treeFromList\n           (map treeFromList [\"baz\",\"zara\",\"bar\"]))\n```\n\n```\nKarakter ikili agaclarinin ikili agaci:\n< < 'b'\n: : |--'a'\n: : `--'z'\n: |--< 'b'\n: |  : |--'a'\n: |  : `--'r'\n: `--< 'z'\n:    : `--'a'\n:    :    `--'r'\n```\n\nAğacın her satırını bu yüzden `:` ile başlatmıştım. (kök hariç)\n\n![Yo](http://yannesposito.com/Scratch/img/blog/Haskell-the-Hard-Way/yo_dawg_tree.jpg)\n\n```haskell\n  putStrLn \"\\nKarakter ikili agaclarinin ikili agaci:\"\n  print $ (treeFromList . map (treeFromList . map treeFromList))\n             [ [\"YO\",\"DAWG\"]\n             , [\"I\",\"HEARD\"]\n             , [\"I\",\"HEARD\"]\n             , [\"YOU\",\"LIKE\",\"TREES\"] ]\n```\n\nki bu da şuna denk:\n\n```haskell\nprint ( treeFromList (\n          map treeFromList\n             [ map treeFromList [\"YO\",\"DAWG\"]\n             , map treeFromList [\"I\",\"HEARD\"]\n             , map treeFromList [\"I\",\"HEARD\"]\n             , map treeFromList [\"YOU\",\"LIKE\",\"TREES\"] ]))\n```\n\nve şu çıktıyı vermeli:\n\n```\nKarakter ikili agaclarinin ikili agaci:\n< < < 'Y'\n: : : `--'O'\n: : `--< 'D'\n: :    : |--'A'\n: :    : `--'W'\n: :    :    `--'G'\n: |--< < 'I'\n: |  : `--< 'H'\n: |  :    : |--'E'\n: |  :    : |  `--'A'\n: |  :    : |     `--'D'\n: |  :    : `--'R'\n: `--< < 'Y'\n:    : : `--'O'\n:    : :    `--'U'\n:    : `--< 'L'\n:    :    : `--'I'\n:    :    :    |--'E'\n:    :    :    `--'K'\n:    :    `--< 'T'\n:    :       : `--'R'\n:    :       :    |--'E'\n:    :       :    `--'S'\n```\n\nTekrar edilen ağaçların eklenmediğine dikkat edin; `\"I\",\"HEARD\"`'e denk gelen sadece bir ağaç var. Bunun için (neredeyse) hiçbir şey yapmadık, çünkü Tree yapısını `Eq` tip sınıfından türettik.\n\nBu yapının ne kadar müthiş olduğunu görebiliyor musunuz: Sadece sayılardan, karakter dizilerinden, karakterlerden değil, başka ağaçlardan da ağaçlar yapabiliyoruz. İstersek ağaçlardan oluşan ağaçlardan oluşan ağaç bile yapabiliriz!\n\n[02_Hard_Part/31_Trees.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/31_Trees.lhs)\n\n***\n\n[02_Hard_Part/40_Infinites_Structures.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/40_Infinites_Structures.lhs)\n\n## 3.3. Sonsuz Yapılar\n\n![Infinite](http://yannesposito.com/Scratch/img/blog/Haskell-the-Hard-Way/escher_infinite_lizards.jpg)\n\nHaskell'in *tembel* olduğu sıkça söylenir.\n\nAslında, eğer biraz titizseniz, Haskell'in [*non-strict*](http://www.haskell.org/haskellwiki/Lazy_vs._non-strict) (aceleci olmayan, kesin olmayan) olduğunu söylemelisiniz. Tembellik sadece *non-strict* dillerin ortak bir tatbikidir.\n\nÖyleyse \"non-strict\" tam olarak ne anlama geliyor? Haskell vikisiden alıntılayalım:\n\n> Sadeleştirme (hesaplama için matematiksel terim) dıştan içe doğru ilerler.\n>\n> yani eğer `(a+(b*c))`'yi ele alıyorsanız, önce `+`'yi sadeleştirirsiniz, sonra iç `(b*c)`'yi sadeleştirirsiniz.\n\nÖrneğin Haskell'de şunu yapabilirsiniz:\n\n```haskell\n-- numbers = [1,2,..]\nnumbers :: [Integer]\nnumbers = 0:map (1+) numbers\n\ntake' n [] = []\ntake' 0 l = []\ntake' n (x:xs) = x:take' (n-1) xs\n\nmain = print $ take' 10 numbers\n```\n\nSonra duruyor.\n\nNeden?\n\n`numbers` değişkeninin tamamını hesaplamak yerine, sadece ihtiyacı olan elemanları, ihtiyacı olduğu zaman hesaplıyor.\n\nAyrıca, Haskell'de sonsuz listeler için bir notasyon olduğunu da söylemiş olayım:\n\n```haskell\n[1..]   ⇔ [1,2,3,4...]\n[1,3..] ⇔ [1,3,5,7,9,11...]\n```\n\nve çoğu fonksiyon da onlarla çalışır. Ayrıca, Haskell'de, bizim `take'` fonksiyonumuza denk bir `take` fonksiyonu mevcuttur.\n\n[02_Hard_Part/40_Infinites_Structures.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/40_Infinites_Structures.lhs)\n\n***\n\n[02_Hard_Part/41_Infinites_Structures.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/41_Infinites_Structures.lhs)\n\nSıralı ikili ağaç yaptığımızı varsayalım. Sonsuz bir ikili ağaç şöyle olur:\n\n```haskell\nnullTree = Node 0 nullTree nullTree\n```\n\nHer düğümün 0'a eşit olduğu, geçerli ve tam bir ikili ağaç. Şimdi bu objeyi aşağıdaki fonksiyonla işleyebileceğimi kanıtlayacağım:\n\n```haskell\n-- bir BinTree'nin tum elemanlarini\n-- belli bir derinlige kadar al\ntreeTakeDepth _ Empty = Empty\ntreeTakeDepth 0 _     = Empty\ntreeTakeDepth n (Node x left right) = let\n          nl = treeTakeDepth (n-1) left\n          nr = treeTakeDepth (n-1) right\n          in\n              Node x nl nr\n```\n\nBu programın sonucunu görelim.\n\n```haskell\nmain = print $ treeTakeDepth 4 nullTree\n```\n\nKodumuz derleniyor, çalışıyor ve şu sonucu vererek duruyor:\n\n```\n<  0\n: |-- 0\n: |  |-- 0\n: |  |  |-- 0\n: |  |  `-- 0\n: |  `-- 0\n: |     |-- 0\n: |     `-- 0\n: `-- 0\n:    |-- 0\n:    |  |-- 0\n:    |  `-- 0\n:    `-- 0\n:       |-- 0\n:       `-- 0\n```\n\nNöronlarınızı biraz daha ısındırmak için daha ilginç bir ağaca bakalım:\n\n```haskell\niTree = Node 0 (dec iTree) (inc iTree)\n        where\n           dec (Node x l r) = Node (x-1) (dec l) (dec r)\n           inc (Node x l r) = Node (x+1) (inc l) (inc r)\n```\n\nBu ağacı oluşturmanın başka bir yolu da üst derece fonksiyonları kullanmaktır. Bu fonksiyon `map` fonksiyonuna benziyor, ama listeler yerine `BinTree`'ler üzerinde çalışıyor. Ortaya şöyle bir fonksiyon çıkacak:\n\n```haskell\n-- bir fonksiyonu agacin her dugumune uygular\ntreeMap :: (a -> b) -> BinTree a -> BinTree b\ntreeMap f Empty = Empty\ntreeMap f (Node x left right) = Node (f x)\n                                     (treeMap f left)\n                                     (treeMap f right)\n```\n\n*Not:* Bunun hakkında burada daha fazla konuşmayacağım. Eğer `map`'in diğer veri yapılarına genellemesiyle ilgileniyorsanız, *functor*ları ve `fmap`'i araştırın.\n\nŞimdi tanımımız şöyle oldu:\n\n```haskell\ninfTreeTwo :: BinTree Int\ninfTreeTwo = Node 0 (treeMap (\\x -> x-1) infTreeTwo)\n                    (treeMap (\\x -> x+1) infTreeTwo)\n```\n\nŞunun sonucuna bakalım:\n\n```haskell\nmain = print $ treeTakeDepth 4 infTreeTwo\n```\n\n```\n<  0\n: |-- -1\n: |  |-- -2\n: |  |  |-- -3\n: |  |  `-- -1\n: |  `-- 0\n: |     |-- -1\n: |     `-- 1\n: `-- 1\n:    |-- 0\n:    |  |-- -1\n:    |  `-- 1\n:    `-- 2\n:       |-- 1\n:       `-- 3\n```\n\n[02_Hard_Part/41_Infinites_Structures.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/02_Hard_Part/41_Infinites_Structures.lhs)\n\n# 4. Çok Zor Kısım\n\nBuraya kadar geldiyseniz tebrikler! Şimdi gerçekten çok zor kısım başlayabilir.\n\nEğer benim gibiyseniz, fonksiyonel stili anlamış olmalısınız. Ayrıca tembelliğin varsayılan olmasının avantajlarını da biraz anlamış olmalısınız. Ama gerçek bir program yapmaya nereden başlamanız gerektiğini bilmiyorsunuz. Özellikle de şu soruların cevaplarını:\n* Yan etkilerle nasıl baş edilir?\n* Neden IO (girdi-çıktı) ile baş etmek için imperatifliğe benzer bir notasyon var?\n\nKarmaşık cevaplara hazır olun. Ama hepsi sonunda çok faydalı.\n\n***\n\n[03_Hell/01_IO/01_progressive_io_example.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/03_Hell/01_IO/01_progressive_io_example.lhs)\n\n## 4.1. IO ile Baş Etmek\n\n![IO](http://yannesposito.com/Scratch/img/blog/Haskell-the-Hard-Way/magritte_carte_blanche.jpg)\n\n> TL;DR: (Çok uzundu okumadım)\n\n> IO ile uğraşan tipik bir fonksiyon imperatif bir programa çok benzer:\n\n```haskell\nf :: IO a\nf = do\n  x <- action1\n  action2 x\n  y <- action3\n  action4 x y\n```\n\n> * Bir nesnenin değerini belirtmek için `<-` kullanıyoruz.\n> * Her satırın tipi `IO *`, bu örnekte:\n   * `action1 :: IO b`\n   * `action2 x :: IO ()`\n   * `action3 :: IO c`\n   * `action4 x y :: IO a`\n   * `x :: b, y :: c`\n   * Az sayıda nesnenin tipi `IO a`'dir, bu seçmenize yardım eder. Farklı olarak, burada saf fonksiyonları doğrudan kullanamazsınız. Saf fonksiyonları kullanmak için örneğin `action2 (saffonksiyon x)` yazabilirsiniz.\n\nBu bölümde size IO kullanmayı anlatacağım, ama nasıl çalıştığını değil. Haskell'in nasıl saf ve saf olmayan kısımları ayırdığını göreceksiniz.\n\nSöz dizimindeki detayları anlamaya çalışmak için durmayın. Cevaplar ilerleyen bölümde gelecek.\n\nNe yapalım?\n\n> Kullanıcıdan bir sayı listesi girmesini isteyin. Sayıların toplamını ekrana yazdırın.\n\n```haskell\ntoList :: String -> [Integer]\ntoList input = read (\"[\" ++ input ++ \"]\")\n\nmain = do\n  putStrLn \"Bir sayi listesi girin (virgulle ayirin):\"\n  input <- getLine\n  print $ sum (toList input)\n```\n\nBu programın ne yaptığı oldukça açık olmalı. Tiplere biraz daha ayrıntılı bakalım.\n\n```\nputStrLn :: String -> IO ()\ngetLine  :: IO String\nprint    :: Show a => a -> IO ()\n```\n\nDaha da ilginç şekilde, `do` bloğunun içindeki her ifadenin `IO a` tipinde olduğuna dikkat edelim.\n\n```haskell\nmain = do\n  putStrLn \"Enter ... \" :: IO ()\n  getLine               :: IO String\n  print Something       :: IO ()\n```\n\nAyrıca `<-` işaretinin etkisine de dikkat edelim.\n\n```\ndo\n x <- something -- bir seyler\n```\n\nEğer `something :: IO a` tipinde ise `x :: a`'dir.\n\n`IO` kullanımıyla ilgili başka bir önemli nokta da şudur: `do` bloğunun içindeki tüm satırlar şu iki şekilden birinde olmalı:\n\n```haskell\naction1             :: IO a\n                    -- bu durumda, a = ()\n```\n\nveya\n\n```haskell\ndeger <- action2    -- ki burada\n                    -- bar z t :: IO b\n                    -- deger   :: b\n```\n\nBu iki çeşit komut aksiyonları sıralamanın iki farklı yolunu ifade ediyor. Bu cümlenin anlamı önümüzdeki bölümün sonunda netleşecek.\n\n[03_Hell/01_IO/01_progressive_io_example.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/03_Hell/01_IO/01_progressive_io_example.lhs)\n\n***\n\n[03_Hell/01_IO/02_progressive_io_example.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/03_Hell/01_IO/02_progressive_io_example.lhs)\n\nŞimdi programımızın nasıl davrandığına bakalım. Örneğin, eğer kullanıcı garip bir şey girerse ne olacak? Deneyelim:\n\n```\n    % runghc 02_progressive_io_example.lhs\n    Enter a list of numbers (separated by comma):\n    foo\n    Prelude.read: no parse\n```\n\nPüf! Garip bir hata mesajından sonra programımız çöktü! İlk iyileştirmemiz daha anlaşılır bir hata mesajı vermek olsun.\n\nBunu yapmak için önce bir şeylerin yanlış gittiğini tespit edebilmemiz gerekiyor. İşte bunu yapmanın bir yolu: `Maybe` (Türkçesi: belki) tipini kullanmak. Bu Haskell'de sık kullanılan bir tiptir.\n\n```haskell\nimport Data.Maybe\n```\n\nPeki bu nedir ki? `Maybe` bir parametre alan bir tiptir. Tanımı da şudur:\n\n```haskell\ndata Maybe a = Nothing | Just a\n```\n\nBu bir değer okumaya veya yaratmaya çalışırken bir hata olduğunu ifade etmenin güzel bir yoludur. `maybeRead` fonksiyonu bunun iyi bir örneği. Bu `read`'e [^fn-5] benzer bir fonksiyon, ama eğer bir şeyler yanlış giderse dönen değer `Nothing` olacak. Eğer bir değer okuyabilirse, dönen değer `Just <değer>` olacak. Bu fonksiyonu çok anlamaya çalışmayın; `read`'den daha alt seviye bir fonksiyon olan `reads`'i kullanıyorum.\n\n```haskell\nmaybeRead :: Read a => String -> Maybe a\nmaybeRead s = case reads s of\n                  [(x,\"\")]    -> Just x\n                  _           -> Nothing\n```\n\nBiraz daha okunaklı olması için, şu şekilde giden bir fonksiyon tanımlayalım: Eğer karakter dizisinin formatı yanlışsa, `Nothing` döndürülecek. Aksi halde, örneğin \"1,2,3\" için `Just [1,2,3]` döndürülecek.\n\n```haskell\ngetListFromString :: String -> Maybe [Integer]\ngetListFromString str = maybeRead $ \"[\" ++ str ++ \"]\"\n```\n\nSonrasında tek yapmamız gereken dönen değeri ana fonksiyonumuzda test etmek.\n\n```haskell\nmain :: IO ()\nmain = do\n  putStrLn \"Bir sayi listesi girin (virgulle ayirin):\"\n  input <- getLine\n  let maybeList = getListFromString input in\n      case maybeList of\n          Just l  -> print (sum l)\n          Nothing -> error \"Kotu format. Hoscakalin.\"\n```\n\nHata durumunda, iyi sayılabilecek bir hata mesajı göstermiş olalım.\n\n`main` fonksiyonunun `do` bloğundaki her ifadenin tipinin `IO a` formatında olduğuna dikkat edin. Tek bilmediğiniz yapı `error`. Ama `error msg` de gerekli tipi alıyor. (burada `IO ()`).\n\nBu programda fark etmeniz gereken şey tanımladığımız fonksiyonların tipleri. Yazdığımız fonksiyonlar arasında sadece bir tanesinin tipinde `IO` var: `main`. Bu demek oluyor ki `main` saf olmayan bir fonksiyon. Ama `main` içinde saf bir fonksiyon olan  `getListFromString` kullanılıyor. Yani sadece bakarak bile fonksiyonların saf olup olmadıklarını anlayabilirsiniz.\n\nPeki saflık neden önemlidir? Bir sürü avantajının üçü şunlar:\n\n* Saf kod hakkında mantık yürütmek saf olmayan kod hakkında mantık yürütmekten çok daha kolaydır.\n* Saflık sizi yan etkilerden ötürü kolayca test edemeyeceğiniz hatalardan korur.\n* Saf fonksiyonları herhangi bir sırayla veya eşzamanlı olarak hiçbir risk olmadan hesaplayabilirsiniz.\n\nİşte bu yüzden, olabildiğince fazla kodunuzu saf fonksiyonlarla yazmalısınız.\n\n[03_Hell/01_IO/02_progressive_io_example.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/03_Hell/01_IO/02_progressive_io_example.lhs)\n\n***\n\n[03_Hell/01_IO/03_progressive_io_example.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/03_Hell/01_IO/03_progressive_io_example.lhs)\n\nSonraki adımımız kullanıcı geçerli bir cevap girene kadar tekrar tekrar sormak olsun.\n\nİlk bölümü aynen kullanabiliriz:\n\n```haskell\nimport Data.Maybe\n\nmaybeRead :: Read a => String -> Maybe a\nmaybeRead s = case reads s of\n                  [(x,\"\")]    -> Just x\n                  _           -> Nothing\ngetListFromString :: String -> Maybe [Integer]\ngetListFromString str = maybeRead $ \"[\" ++ str ++ \"]\"\n```\n\nŞimdi kullanıcı doğru bir girdi yazana kadar tekrar soran bir fonksiyon yazalım:\n\n```\naskUser :: IO [Integer]\naskUser = do\n  putStrLn \"Bir sayi listesi girin (virgulle ayirin):\"\n  input <- getLine\n  let maybeList = getListFromString input in\n      case maybeList of\n          Just l  -> return l\n          Nothing -> askUser\n```\n\nFonksiyonumuzun tipi `IO [Integer]`. Bu demek oluyor ki belirli IO aksiyonları sonucu `[Integer]` tipinde bir değer elde ediyoruz. Bazıları bunu şöyle açıklıyor:\n\n> «IO içinde [Integer] var.»\n\nEğer bunun arkasındaki detayları anlamak istiyorsanız, sonraki bölümü okumanız gerekecek. Ama eğer IO'yu sadece *kullanmak* istiyorsanız, biraz tekrar yapın ve tipler hakkında düşünmeniz gerektiğini hatırlayın.\n\nSon olarak, `main` fonksiyonumuz çok daha basit:\n\n```haskell\nmain :: IO ()\nmain = do\n  list <- askUser\n  print $ sum list\n```\n\nIO'ya girişimizi bitirdik. Biraz hızlıydı, değil mi? Hatırlamamız gereken temel şeyler sunlar:\n\n* `do` bloğunun içinde, her ifade `IO a` tipinde olmalı. Bu sizi belli ifadelerle kısıtlıyor. Örneğin, `getLine`, `print`, `putStrLn`, vs.\n* Saf fonksiyonları olabildiğince saf olmayan kısımların dışında tutmaya çalışın, işin mümkün olduğunca büyük kısmını saf fonksiyonlara yaptırın.\n* `IO a`, `a` tipinde bir eleman döndüren IO aksiyonu demektir. `IO` aksiyonu temsil eder, `IO a` aslında bir fonksiyonun tipidir. Daha fazlasını merak ediyorsanız sonraki bölümü okuyun.\n\nBiraz çalışırsanız, `IO` kullanabiliyor olmalısınız.\n\n> Alıştırma: Tüm argümanlarının toplamını alan bir program yazın. İpucu: `getArgs` fonksiyonunu kullanın.\n\n[03_Hell/01_IO/03_progressive_io_example.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/03_Hell/01_IO/03_progressive_io_example.lhs)\n\n## 4.2. IO'nun Püf Noktası\n\n![Bu bir pipo degildir](http://yannesposito.com/Scratch/img/blog/Haskell-the-Hard-Way/magritte_pipe.jpg)\n\n> Bu bölüm için TL; DR (Çok uzundu okumadım)\n\n> Saf ve saf olmayan kısımları ayırmak için, `main` dünyanın durumunu değiştiren bir fonksiyon olarak tanımlanır.\n\n```haskell\nmain :: World -> World\n```\n\n> Bir fonksiyon, sadece ve sadece bu tipe sahipse yan etkide bulunur. Tipik bir `main` fonksiyonuna bakalım:\n\n```haskell\nmain w0 =\n    let (v1,w1) = action1 w0 in\n    let (v2,w2) = action2 v1 w1 in\n    let (v3,w3) = action3 v2 w2 in\n    action4 v3 w3\n```\n\n> Sonraki aksiyona aktarmamız gereken bir sürü geçici elemanımız var. (burada `w1`, `w2` ve `w3`)\n\n> `bind` veya `(>>=)` fonksiyonu yaratıyoruz. `bind` ile artık geçici isimlere ihtiyacımız yok.\n\n```haskell\nmain =\n  action1 >>= action2 >>= action3 >>= action4\n```\n\n> Bonus: Haskell'in şöyle bir söz dizimsel kolaylığı var:\n\n```haskell\nmain = do\n  v1 <- action1\n  v2 <- action2 v1\n  v3 <- action3 v2\n  action4 v3\n```\n\n***\n\nNeden böyle garip bir söz dizimi kullandık ve bu `IO` tipi tam olarak nedir? Anlaşılmaz duruyor ama, değil.\n\nŞimdilik, programımızın saf kısımlarını bir kenara bırakıp saf olmayan kısımlar üzerinde yoğunlaşalım:\n\n```haskell\naskUser :: IO [Integer]\naskUser = do\n  putStrLn \"Bir sayi listesi girin (virgulle ayirin):\"\n  input <- getLine\n  let maybeList = getListFromString input in\n      case maybeList of\n          Just l  -> return l\n          Nothing -> askUser\n\nmain :: IO ()\nmain = do\n  list <- askUser\n  print $ sum list\n```\n\nİlk tepki: İmperatif duruyor. Haskell saf olmayan kodu imperatif gösterecek kadar güçlüdür. Örneğin, isterseniz Haskell'de `while` yapısı yaratabilirsiniz. Hatta, `IO` ile uğraşman için imperatif stip genellikle daha uygundur.\n\nAma notasyonun alışılmışın dışında olduğunu fark etmiş olmalısınız. Şimdi bunun sebeplerini detaylıca tartışalım.\n\nSaf olmayan bir dilde, dünyanın durumu devasa ve gizli bir global değişken olarak görülebilir. Bu gizli değişkene dildeki tüm fonksiyonlar tarafından erişilebilir. Örneğin herhangi bir fonksiyon içinde bir dosya ile okuma/yazma işlemleri yapabilirsiniz. Dosyanın var olup olmaması \"dünya\"nızın alabileceği olası durumlardır.\n\nHaskell'de bu durum gizli değildir. Tam tersine, Haskell'de `main`'in dünyanızın durumunu değiştirme olasılığı olduğu özellikle ayrıca söylenir. Bu fonksiyonun tipi şunun gibi bir şeydir:\n\n```haskell\nmain :: World -> World\n```\n\nBu değişkene tüm fonksiyonların erişimi yoktur. Erişimi olan fonksiyonlar saf değildir. Dünya değişkenine erişimi olmayan fonksiyonlar ise saftır. [^fn-6]\n\nHaskell, dünyanın durumunu `main` fonksiyonuna bir girdi değişkeni olarak görür. Ama `main`'in asıl tipi suna daha yakındır: [^fn-7]\n\n```haskell\nmain :: World -> ((),World)\n```\n\n`()` tipi birim tipidir. Burda görülecek bir şey yok.\n\nŞimdi bunu aklımızda tutarak `main` fonksiyonumuzu baştan yazalım:\n\n```haskell\nmain w0 =\n    let (list,w1) = askUser w0 in\n    let (x,w2) = print (sum list,w1) in\n    x\n```\n\nİlk olarak, yan etkisi olan tüm fonksiyonların şu tipte olması gerektiğini hatırlayalım:\n\n```haskell\nWorld -> (a,World)\n```\n\nBurada `a` sonucun tipi oluyor. Örneğin `getChar` fonksiyonu bu durumda `World -> (Char,World)` tipindedir.\n\nDikkat edilmesi gereken diğer bir şey ise hesaplama/değerlendirme sırası. Örneğin `f a b`'yi hesaplarken birden fazla seçeneğiniz var:\n\n* önce `a`'yi, sonra `b`'yi, sonra da `f a b`'yi hesapla.\n* önce `b`'yi, sonra `a`'yi, sonra da `f a b`'yi hesapla.\n* `a`'yi ve `b`'yi paralel olarak, sonra da `f a b`'yi hesapla.\n\nBu böyle çünkü dilin saf kısmında çalışıyoruz.\n\nŞimdi, eğer `main` fonksiyonuna bakarsanız, ilk satırı ikinci satırdan önce hesaplamanız gerektiği açık, çünkü ikinci satırda birinci satırda elde ettiğiniz bir değeri parametre olarak kullanıyorsunuz.\n\nBu işe yarıyor. Derleyici her adımda yeni bir gerçek dünya tanımı/kodu (*id*) sağlıyor. Gizli olarak, `print` şöyle işliyor:\n\n* ekrana bir şey yazdır\n* dünyanın id'sini değiştir.\n* `((), yeni dünya id'si)` değerini döndür.\n\nŞimdi, eğer `main` fonksiyonunun stiline bakarsanız, biraz garip olduğunu göreceksiniz. Aynısını `askUser` fonksiyonuna da uygulayalım:\n\n```haskell\naskUser :: World -> ([Integer],World)\n```\n\nÖncesi:\n\n```haskell\naskUser :: IO [Integer]\naskUser = do\n  putStrLn \"Bir sayi listesi girin:\"\n  input <- getLine\n  let maybeList = getListFromString input in\n      case maybeList of\n          Just l  -> return l\n          Nothing -> askUser\n```\n\nSonrası:\n\n```haskell\naskUser w0 =\n    let (_,w1)     = putStrLn \"Bir sayi listesi girin:\" in\n    let (input,w2) = getLine w1 in\n    let (l,w3)     = case getListFromString input of\n                      Just l   -> (l,w2)\n                      Nothing  -> askUser w2\n    in\n        (l,w3)\n```\n\nBenzer, ama biraz daha garip. Tüm şu geçici `w?`'lere bakın.\n\nÇıkarılacak ders şu: Saf fonksiyonel dillerdeki naif IO uygulamaları gariptir!\n\nŞanslıyız ki, bu sorunu halletmek için daha iyi bir yol var. Bir kalip goruyoruz, her satir su sekilde:\n\n```haskell\nlet (y,w') = action x w in\n```\n\nHerhangi bir satır için ilk `x` argümanı gerekmese bile. Dönen sonucun tipi bir ikili, `(sonuç, yeniDünyaDeğeri)`. Her `f` fonksiyonu şuna benzer bir tipe sahip olmak zorunda:\n\n```haskell\nf :: World -> (a,World)\n```\n\nHer zaman aynı kalıbı takip ettiğimize dikkat edin:\n\n```haskell\nlet (y,w1) = action1 w0 in\nlet (z,w2) = action2 w1 in\nlet (t,w3) = action3 w2 in\n...\n```\n\nHer aksiyon 0'dan n'ye kadar parametre alabilir. Ve özellikle, her aksiyon bir üstündeki satırın sonucundan parametre alabilir.\n\nÖrneğin, şöyle diyebiliriz:\n\n```haskell\nlet (_,w1) = action1 x w0   in\nlet (z,w2) = action2 w1     in\nlet (_,w3) = action3 x z w2 in\n...\n```\n\nVe tabii ki `actionN w :: (World) -> (a,World)`.\n\n> Önemli: Dikkat edilmesi gereken iki kalıp var:\n\n```haskell\nlet (x,w1) = action1 w0 in\nlet (y,w2) = action2 x w1 in\n```\n\n> ve\n\n```haskell\nlet (_,w1) = action1 w0 in\nlet (y,w2) = action2 w1 in\n```\n\n***\n\n![Joker](http://yannesposito.com/Scratch/img/blog/Haskell-the-Hard-Way/jocker_pencil_trick.jpg)\n\nŞimdi biraz sihirbazlık yapalım. Geçici dünya sembolünü \"yok edelim\". İki satırı `bind` ile birbirine bağlayacağız. İşe `bind` fonksiyonunu tanımlayarak başlayalım. Fonksiyonun tipi başta biraz korkutucu gelebilir:\n\n```haskell\nbind :: (World -> (a,World))\n        -> (a -> (World -> (b,World)))\n        -> (World -> (b,World))\n```\n\nAma hatırlayın ki `(World -> (a,World))` IO aksiyonlarının tipidir. Daha açık olması için ona yeni bir isim verelim:\n\n```haskell\ntype IO a = World -> (a, World)\n```\n\nBazı fonksiyon örnekleri:\n\n```haskell\ngetLine :: IO String\nprint :: Show a => a -> IO ()\n```\n\n`getLine` dünyayı parametre olarak alan ve `(String,World)` ikilisini döndüren bir IO aksiyonudur. Bu şöyle özetlenebilir: `getLine`, `IO String` tipindedır, ki bunu \"IO içine gömülmüş\" String döndüren bir IO aksiyonu olarak görebiliriz.\n\n`print` fonksiyonu da ayrıca ilginçtir. Gösterilebilir bir argüman alır, ama aslında iki argüman almaktadır. İlki ekrana yazdırılacak değerdir, ikincisi de dünyanın durumudur. Sonrasında ise `((),World)` ikilisini döndürür. Bu fonksiyonun dünyanın durumunu değiştirdiği ama başka bir veri üretmediği anlamına gelir.\n\nBu tip, `bind` fonksiyonun tipini basitleştirmemize yardımcı olur:\n\n```haskell\nbind :: IO a\n        -> (a -> IO b)\n        -> IO b\n```\n\nBu demek oluyor ki `bind` fonksiyonu iki IO aksiyonunu parametre olarak alıyor ve başka bir IO aksiyonunu geri döndürüyor.\n\nÖnemli kalıpları tekrar hatırlayın. İlki şuydu:\n\n```haskell\nlet (x,w1) = action1 w0 in\nlet (y,w2) = action2 x w1 in\n(y,w2)\n```\n\nFonksiyonların tiplerine bakalım:\n\n```haskell\naction1  :: IO a\naction2  :: a -> IO b\n(y,w2)   :: IO b\n```\n\nTanıdık gelmiyor mu?\n\n```haskell\n(bind action1 action2) w0 =\n    let (x, w1) = action1 w0\n        (y, w2) = action2 x w1\n    in  (y, w2)\n```\n\nAmacımız World argümanını bu fonksiyonla gizlemek. Örnek olarak, şunu gerçekleştirmek istediğimizi varsayalım:\n\n```haskell\nlet (line1,w1) = getLine w0 in\nlet ((),w2) = print line1 in\n((),w2)\n```\n\nŞimdi, `bind` fonksiyonunu kullanarak:\n\n```haskell\n(res,w2) = (bind getLine (\\l -> print l)) w0\n```\n\n`print` fonksiyonu `(World -> ((),World))` tipinde olduğu için, `res = ()` (boş tip) Eğer bundaki sihirbazlığı görmediyseniz, bu sefer üç satırla deneyelim:\n\n```haskell\nlet (line1,w1) = getLine w0 in\nlet (line2,w2) = getLine w1 in\nlet ((),w3) = print (line1 ++ line2) in\n((),w3)\n```\n\nBu da şuna denk:\n\n```haskell\n(res,w3) = (bind getLine (\\line1 ->\n             (bind getLine (\\line2 ->\n               print (line1 ++ line2))))) w0\n```\n\nBir şey fark ettiniz mi? Evet, artık hiçbir yerde geçici World değişkenleri kullanılmıyor. Sihirbazlık gibi.\n\nDaha iyi bir notasyon kullanabiliriz. `bind` yerine `(>>=)` kullanalım. `(>>=)`, `(+)` gibi bir iç notasyonlu fonksiyondur; ki şöyle çalışır: `3 + 4 ⇔ (+) 3 4`\n\nHo Ho Ho! Herkese Mutlu Noeller! Haskell bize söz dizimsel kolaylık sağlıyor:\n\n```haskell\ndo\n  x <- action1\n  y <- action2\n  z <- action3\n  ...\n```\n\nyerine, şöyle yazabiliriz:\n\n```haskell\naction1 >>= (\\x ->\naction2 >>= (\\y ->\naction3 >>= (\\z ->\n...\n)))\n```\n\n`action2` içinde `x`, `action3` içinde hem `x` hem de `y` değişkenlerini kullanabildiğinize dikkat edin.\n\nPeki `<-` kullanmayan satırlarda ne yapacağız? Kolay, `blindBind` diye başka bir fonksiyon tanımlayalım:\n\n```haskell\nblindBind :: IO a -> IO b -> IO b\nblindBind action1 action2 w0 =\n    bind action (\\_ -> action2) w0\n```\n\nBu tanımı daha açık olması için basitleştirmedim. Tabii daha basit bir notasyon kullanabiliriz, bunun için `(>>)` operatörü var.\n\n```haskell\ndo\n    action1\n    action2\n    action3\n```\n\nŞuna dönüşüyor:\n\n```haskell\naction1 >>\naction2 >>\naction3\n```\n\nKullanışlı bir fonksiyon daha var.\n\n```haskell\nputInIO :: a -> IO a\nputInIO x = IO (\\w -> (x,w))\n```\n\nBu saf değerleri IO bağlamına sokmak için kullanılan genel bir yoldur. `putInIO` için kullanılan genel isim `return`'dür. Haskell öğrenirken bu oldukça kötü bir isim, çünkü Haskell'deki `return` alışık olduğunuzden çok farklıdır.\n\n[03_Hell/01_IO/21_Detailled_IO.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/03_Hell/01_IO/21_Detailled_IO.lhs)\n\nÖrneğimizi çevirerek bu bölümü bitirelim:\n\n```haskell\naskUser :: IO [Integer]\naskUser = do\n  putStrLn \"Bir sayi listesi girin (virgullerle ayirin):\"\n  input <- getLine\n  let maybeList = getListFromString input in\n      case maybeList of\n          Just l  -> return l\n          Nothing -> askUser\n\nmain :: IO ()\nmain = do\n  list <- askUser\n  print $ sum list\n```\n\nŞu hale geliyor:\n\n```haskell\nimport Data.Maybe\n\nmaybeRead :: Read a => String -> Maybe a\nmaybeRead s = case reads s of\n                  [(x,\"\")]    -> Just x\n                  _           -> Nothing\ngetListFromString :: String -> Maybe [Integer]\ngetListFromString str = maybeRead $ \"[\" ++ str ++ \"]\"\naskUser :: IO [Integer]\naskUser =\n    putStrLn \"Bir sayi listesi girin (virgullerle ayirin):\" >>\n    getLine >>= \\input ->\n    let maybeList = getListFromString input in\n      case maybeList of\n        Just l -> return l\n        Nothing -> askUser\n\nmain :: IO ()\nmain = askUser >>=\n  \\list -> print $ sum list\n```\n\nÇalıştığını doğrulamak için derleyebilirsiniz.\n\n`(>>)` ve `(>>=)` olmadan nasıl olacağını düşünün.\n\n\n[03_Hell/01_IO/21_Detailled_IO.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/03_Hell/01_IO/21_Detailled_IO.lhs)\n\n***\n\n[03_Hell/02_Monads/10_Monads.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/03_Hell/02_Monads/10_Monads.lhs)\n\n## 4.3. Monad\n\n![Monad](http://yannesposito.com/Scratch/img/blog/Haskell-the-Hard-Way/dali_reve.jpg)\n\nArtık bu sırrı açıklayabiliriz: `IO` bir *monad*dir. Monad olmak, `do` notasyonu ile belirli söz dizimsel kolaylıklara sahip olmak demektir. Ama temel olarak, kodunuzun akışını kolaylaştıracak belirli kod kalıplarına erişim sağlar.\n\n> Önemli noktalar:\n> * Monadlar etkilerle ilgili olmak zorunda değildir! Saf monadlar da vardır.\n> * Monadlar daha çok sıralama ile ilgilidir.\n\nHaskell'de `Monad` bir tip sınıfıdır. Bu sınıfın bir üyesi olmak için `(>>=)` ve `return` fonksiyonlarını sağlamalısınız. `(>>)` fonksiyonu `(>>=)` fonksiyonundan türer. Basit olarak `Monad` tip sınıfı şöyle belirtilir:\n\n```haskell\nclass Monad m  where\n  (>>=) :: m a -> (a -> m b) -> m b\n  return :: a -> m a\n\n  (>>) :: m a -> m b -> m b\n  f >> g = f >>= \\_ -> g\n\n  -- Sadece tarihsel sebeplerden dolayi oldugunu dusundugum\n  -- bu fonksiyonu dikkate almayabilirsiniz\n  fail :: String -> m a\n  fail = error\n```\n\n> Notlar:\n> * `class` anahtar kelimesi dostunuz değildir. Haskell'deki class nesne yönelimli programlamada karşılaştığınız class gibi değildir. Haskell'deki class Java'daki interface'le benzeşir. `typeclass` daha iyi bir isimlendirme olurdu, çünkü o tip grubu anlamına geliyor. Bir tipin bir sınıfa ait olması için, bir sınıfın tüm fonksiyonlarının o tip için sağlanabilir olması gerekiyor.\n> * Tip sınıflarının bu örneğinde, `m` tipinin argüman alan bir tip olması gerekiyor, örneğin `IO a`, ama aynı zamanda `Maybe a`, `[a]`, vs.\n> * Fonksiyonunuzun kullanışlı bir monad olması için bazı kurallara uyması gerekiyor. Eğer yapınız bu kurallara uymuyorsa garip şeyler gerçekleşebilir: `~ return a >>= k == k a m >>= return == m m >>= (-> k x >>= h) == (m >>= k) >>= h ~`\n\n### 4.3.1 Maybe Monad'ı\n\n`Monad` tip sınıfının üyesi olan bir sürü farklı tip vardır. Tarif etmesi en kolay olanlarından biri de `Maybe`'dir. Eğer `Maybe` değerlerinden oluşan bir diziniz varsa, etkilemek için monadları kullanabilirsiniz. Uzayıp giden `ıf..then..else..` yapılarından kurtulmak için oldukça kullanışlı bir yoldur.\n\nKarmaşık bir banka işlemi düşünün. Eğer bakiyeniz sıfırın altına düşmeden belli işlemleri yapabilecek kadar paranız varsa, 700€ kazanma hakkınız olsun.\n\n```haskell\ndeposit  value account = account + value --para yatirma\nwithdraw value account = account - value --para cekme\n\n--para kazanmaya hak kazanip kazanmadiginizi donduren fonksiyon\neligible :: (Num a,Ord a) => a -> Bool\neligible account =\n  let account1 = deposit 100 account in\n    if (account1 < 0)\n    then False\n    else\n      let account2 = withdraw 200 account1 in\n      if (account2 < 0)\n      then False\n      else\n        let account3 = deposit 100 account2 in\n        if (account3 < 0)\n        then False\n        else\n          let account4 = withdraw 300 account3 in\n          if (account4 < 0)\n          then False\n          else\n            let account5 = deposit 1000 account4 in\n            if (account5 < 0)\n            then False\n            else\n              True\n\nmain = do\n  print $ eligible 300 -- True\n  print $ eligible 299 -- False\n```\n\n[03_Hell/02_Monads/10_Monads.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/03_Hell/02_Monads/10_Monads.lhs)\n\n***\n\n[03_Hell/02_Monads/11_Monads.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/03_Hell/02_Monads/11_Monads.lhs)\n\nŞimdi `Maybe` kullanarak ve monadlardan faydalanarak iyileştirelim:\n\n```haskell\ndeposit :: (Num a) => a -> a -> Maybe a\ndeposit value account = Just (account + value)\n\nwithdraw :: (Num a,Ord a) => a -> a -> Maybe a\nwithdraw value account = if (account < value)\n                         then Nothing\n                         else Just (account - value)\n\neligible :: (Num a, Ord a) => a -> Maybe Bool\neligible account = do\n  account1 <- deposit 100 account\n  account2 <- withdraw 200 account1\n  account3 <- deposit 100 account2\n  account4 <- withdraw 300 account3\n  account5 <- deposit 1000 account4\n  Just True\n\nmain = do\n  print $ eligible 300 -- Just True\n  print $ eligible 299 -- Nothing\n```\n\n[03_Hell/02_Monads/11_Monads.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/03_Hell/02_Monads/11_Monads.lhs)\n\n***\n\n[03_Hell/02_Monads/12_Monads.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/03_Hell/02_Monads/12_Monads.lhs)\n\nKötü değil, ama daha da iyileştirebiliriz:\n\n```haskell\ndeposit :: (Num a) => a -> a -> Maybe a\ndeposit value account = Just (account + value)\n\nwithdraw :: (Num a,Ord a) => a -> a -> Maybe a\nwithdraw value account = if (account < value)\n                         then Nothing\n                         else Just (account - value)\n\neligible :: (Num a, Ord a) => a -> Maybe Bool\neligible account =\n  deposit 100 account >>=\n  withdraw 200 >>=\n  deposit 100  >>=\n  withdraw 300 >>=\n  deposit 1000 >>\n  return True\n\nmain = do\n  print $ eligible 300 -- Just True\n  print $ eligible 299 -- Nothing\n```\n\nMonadların kodumuzu daha zarifleştirmenin iyi bir yolu olduğunu gösterdik. Dikkat edin ki, bu tip bir kod düzenlemesi, özellikle `Maybe`, pek çok imperatif dilde de uygulanabilir. Aslında, bu tip bir yapıyı normalde de yapıyoruz.\n\n> Önemli bir nokta: Dizideki ilk elemanın `Nothing` olarak hesaplanması tüm hesaplamayı durduracaktır. Bu demek oluyor ki, tüm satırları hesaplamıyorsunuz. Tembellik sayesinde bunun için fazladan bir şey yapmanıza gerek yok.\n\nBunu göz önünde bulundurarak `Maybe` için `(>>=)` fonksiyonunu şöyle tanımlayabilirsiniz:\n\n```haskell\ninstance Monad Maybe where\n    (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b\n    Nothing  >>= _  = Nothing\n    (Just x) >>= f  = f x\n\n    return x = Just x\n```\n\nBu basit örnek ile `Maybe` monadının ne kadar kullanışlı olabileceğini ve nasıl kullanılabileceğini gördük. Ama daha iyi bir örnek için listelere bakalım.\n\n[03_Hell/02_Monads/12_Monads.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/03_Hell/02_Monads/12_Monads.lhs)\n\n***\n\n[03_Hell/02_Monads/13_Monads.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/03_Hell/02_Monads/13_Monads.lhs)\n\n### 4.3.2. Liste Monad'ı\n\n![liste](http://yannesposito.com/Scratch/img/blog/Haskell-the-Hard-Way/golconde.jpg)\n\nListe monadı deterministik (belirlenimci) olmayan hesaplamaları simüle etmemize yardımcı olur. Şöyle:\n\n```haskell\nimport Control.Monad (guard)\n\nallCases = [1..10]\n\nresolve :: [(Int,Int,Int)]\nresolve = do\n              x <- allCases\n              y <- allCases\n              z <- allCases\n              guard $ 4*x + 2*y < z\n              return (x,y,z)\n\nmain = do\n  print resolve\n```\n\nResmen sihirbazlık.\n\n```haskell\n[(1,1,7),(1,1,8),(1,1,9),(1,1,10),(1,2,9),(1,2,10)]\n```\n\nListe monadı için, şöyle bir söz dizimsel kolaylık da vardır:\n\n```haskell\n  print $ [ (x,y,z) | x <- allCases,\n                      y <- allCases,\n                      z <- allCases,\n                      4*x + 2*y < z ]\n```\n\nTüm monadları sıralamayacağım, ancak bir sürü monad bulunmakta. Saf dillerdeki belli kavramlar monad kullanımı ile basitleştirilebilir. Özellikle monadlar şunlar için kullanışlıdır:\n\n* IO\n* deterministik olmayan hesaplamalar\n* (sözde) rastgele sayı üretimi\n* konfigürasyon durumunu tutma\n* yazma durumu\n* ..\n\nEğer buraya kadar beni takip edebildiyseniz, başardınız! Monadları öğrendiniz! [^fn-8]\n\n[03_Hell/02_Monads/13_Monads.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/03_Hell/02_Monads/13_Monads.lhs)\n\n# 5. Ekler\n\nBu bölüm doğrudan Haskell'le ilgili değil. Bazı ayrıntılı açıklamalar için okuyabilirsiniz.\n\n[04_Appendice/01_More_on_infinite_trees/10_Infinite_Trees.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/04_Appendice/01_More_on_infinite_trees/10_Infinite_Trees.lhs)\n\n## 5.1. Sonsuz Ağaçlar Hakkında\n\n[Sonsuz Yapılar](#33-sonsuz-yap%C4%B1lar) kısmında bazı basit yapılar görmüştük. Ancak ağacımızdan iki özellik çıkartmıştık:\n\n1. tekrar eden düğümlerin olmaması\n2. düzgün sıralı ağaç olması\n\nBu bölümde ilk özelliği sağlamaya çalışacağız. İkincisiyle ilgili olarak da şimdilik bir şey yapmayacağız ama nasıl olabildiğince sıralı tutabileceğimizi tartışacağız.\n\nİlk adımımız (sözde) rastgele bir sayı listesi oluşturmak olsun:\n\n```haskell\nshuffle = map (\\x -> (x*3123) `mod` 4331) [1..]\n```\n\n`treeFromList` fonksiyonunun tanımını hatırlayalım:\n\n```haskell\ntreeFromList :: (Ord a) => [a] -> BinTree a\ntreeFromList []    = Empty\ntreeFromList (x:xs) = Node x (treeFromList (filter (<x) xs))\n                             (treeFromList (filter (>x) xs))\n```\n\n`treeTakeDepth` de şöyleydi:\n\n```haskell\ntreeTakeDepth _ Empty = Empty\ntreeTakeDepth 0 _     = Empty\ntreeTakeDepth n (Node x left right) = let\n          nl = treeTakeDepth (n-1) left\n          nr = treeTakeDepth (n-1) right\n          in\n              Node x nl nr\n```\n\nProgramımız da şu şekilde:\n\n```haskell\nmain = do\n      putStrLn \"take 10 shuffle\"\n      print $ take 10 shuffle\n      putStrLn \"\\ntreeTakeDepth 4 (treeFromList shuffle)\"\n      print $ treeTakeDepth 4 (treeFromList shuffle)\n```\n\n```\n% runghc 02_Hard_Part/41_Infinites_Structures.lhs\ntake 10 shuffle\n[3123,1915,707,3830,2622,1414,206,3329,2121,913]\ntreeTakeDepth 4 (treeFromList shuffle)\n\n< 3123\n: |--1915\n: |  |--707\n: |  |  |--206\n: |  |  `--1414\n: |  `--2622\n: |     |--2121\n: |     `--2828\n: `--3830\n:    |--3329\n:    |  |--3240\n:    |  `--3535\n:    `--4036\n:       |--3947\n:       `--4242\n```\n\nHey! Sonlanıyor! Ama dikkat edin, program sadece dallara koyacak veri olduğu sürece çalışacak.\n\nÖrneğin:\n\n```haskell\ntreeTakeDepth 4 (treeFromList [1..])\n```\n\nsonsuza kadar çalışacak, çünkü `filter (<1) [2..]` ifadesinin ilk elemanını almaya çabalayacak. Ama `filter` fonksiyonu sonucun boş liste olduğunu anlayacak kadar akıllı değil.\n\nBunlar da okur için alıştırma olarak kalsın:\n\n* `treeTakeDepth n (treeFromList shuffle)` ifadesini sonsuz döngüye sokacak bir `n` değeri olduğunu kanıtlayın.\n* `n` için bir üst sınır bulun.\n* Hiçbir `shuffle` listesinin programı bitiremeyeceğini kanıtlayın.\n\n[04_Appendice/01_More_on_infinite_trees/10_Infinite_Trees.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/04_Appendice/01_More_on_infinite_trees/10_Infinite_Trees.lhs)\n\n***\n\n[04_Appendice/01_More_on_infinite_trees/11_Infinite_Trees.lhs](http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/code/04_Appendice/01_More_on_infinite_trees/11_Infinite_Trees.lhs)\n\nBu sorunları çözmek için `treeFromList` ve `shuffle` fonksiyonlarımızı biraz değiştireceğiz.\n\nİlk sorunumuz, `shuffle` fonksiyon tanımımızda sonsuz farklı sayı üreten bir yapı olmaması. Sadece `4331` farklı sayı ürettik. Bunu çözmek için daha iyi bir `shuffle` fonksiyonu yazalım.\n\n```haskell\nshuffle = map rand [1..]\n          where\n              rand x = ((p x) `mod` (x+c)) - ((x+c) `div` 2)\n              p x = m*x^2 + n*x + o -- bir polinom\n              m = 3123\n              n = 31\n              o = 7641\n              c = 1237\n```\n\nBu `shuffle` fonksiyonunun (umarız ki) bir alt veya üst limiti yok. Ama daha iyi bir rastgele sayı fonksiyonu sonsuz döngüye girmeyi engellemiyor.\n\nGenel olarak, `filter (<x) xs`'in boş liste olup olmadığını anlamıyoruz. Öyleyse bu sorunu çözmek için, ikili ağacımızı oluştururken hata vermeyi deneyelim. Kodumuzun bu yeni versiyonu düğümleri için şu özelliğe sahip olan bir ikili ağaç oluşturacak:\n\n> Sol alt ağaçtaki herhangi bir eleman, kökün değeriden daha küçük olmalı.\n\nDikkat edin ki genel olarak sıralı bir ikili ağaç olarak kalacak. Ayrıca, yapı itibarıyla, her düğüm değeri ağaçta tek olacak, tekrarlanmayacak.\n\n```haskell\ntreeFromList :: (Ord a, Show a) => [a] -> BinTree a\ntreeFromList []    = Empty\ntreeFromList (x:xs) = Node x left right\n          where\n              left = treeFromList $ safefilter (<x) xs\n              right = treeFromList $ safefilter (>x) xs\n```\n\nBu yeni `safefilter` fonksiyonu `filter` fonksiyonuna neredeyse denk, ancak eğer liste sonsuzsa sonsuz döngüye girmiyor. Eğer art arda 10000 değerin testi olumsuz çıkarsa, bunu aramanın sonu sayıyor.\n\n```haskell\nsafefilter :: (a -> Bool) -> [a] -> [a]\nsafefilter f l = safefilter' f l nbTry\n  where\n      nbTry = 10000\n      safefilter' _ _ 0 = []\n      safefilter' _ [] _ = []\n      safefilter' f (x:xs) n =\n                  if f x\n                     then x : safefilter' f xs nbTry\n                     else safefilter' f xs (n-1)\n```\n\nŞimdi programı çalıştırıp mutlu olabilirsiniz:\n\n```haskell\nmain = do\n      putStrLn \"take 10 shuffle\"\n      print $ take 10 shuffle\n      putStrLn \"\\ntreeTakeDepth 8 (treeFromList shuffle)\"\n      print $ treeTakeDepth 8 (treeFromList $ shuffle)\n```\n\nEkrana yazdırılan her değerin yazma zamanının farklı olduğunu fark etmelisiniz. Bunun sebebi Haskell'in her değeri sadece ihtiyacı olduğu zaman hesaplaması. Ve bu durumda, bu zaman ekrana yazdırılacağı zaman.\n\nDaha da etkileyici bir şey görmek için `depth` değerini `8`'den `100`'e cikarın. RAM'inizi boğmadan çalışacak! Akış ve hafıza yönetimi Haskell tarafından doğal olarak yapılıyor.\n\nBu da okura alıştırma olarak kalsın:\n\n* `deep` ve `nbTry` için yüksek sabit değer ile bile, iyi şekilde çalışıyor gibi gözüküyor. Ama en kötü durumda üstel olabilir. `treeFromList` için olabilecek kötü bir liste oluşturun. *ipucu*: [0,-1,-1,....,-1,1,-1,...,-1,1,...] listesini düşünün.\n* `safefilter` fonksiyonunu şöyle tanımlamayı denedim:\n\n```haskell\n  safefilter' f l = if filter f (take 10000 l) == []\n                    then []\n                    else filter f l\n```\nNeden çalışmadığını ve sonsuz döngüye girebileceğini açıklayın.\n* `shuffle`'in artan sınırlarla gerçek bir rastgele liste olduğunu farz edin. Bu yapı üzerinde biraz çalışırsanız, bu yapının 1 olasılıkla sonlu olduğunu fark edeceksiniz. Aşağıdaki kodu kullanarak (hiç `safefilter` yokmuş gibi doğrudan `safefilter'` kullanın) `f` için 1 olasılıkla treeFromList' shuffle'ın sonlu olduğu bir tanım bulun, ve kanıtlayın. Dikkat: bu sadece bir konjektür.\n\n# 6. Teşekkürler\n\n[r/haskell](http://reddit.com/r/haskell) ve [r/programming](http://reddit.com/r/programming) gruplarına teşekkür ediyorum. Yorumları bana çok yardımcı oldu.\n\nÖzellikle, [Emm](https://github.com/Emm)'e, İngilizce'mi düzeltmekle uğraştığı zaman için binlerce kez teşekkür ederim.\n\n> Çevirmen Notu: Klavyemde Türkçe karakterler olmadığı için mecburen [deasciifier](https://github.com/joom/turkish-deasciifier.vim) kullanıyorum. Yazıda herhangi bir Türkçe karakter veya çeviri hatası bulursanız, beni bilgilendirirseniz, veya *pull request* yollayarak düzeltirseniz çok sevinirim. Daha iyi çevirilebileceğini düşündüğünüz bölümler için de bu geçerli. Teşekkürler.\n\n***\n\n#### Dipnotlar\n\n[^fn-1]: Son zamanda çıkan diller onları saklamaya çalışsa da, onlar oradalar.\n\n[^fn-2]: Hile yaptığımı biliyorum. Ama tembellikle ilgili sonra konuşacağız.\n\n[^fn-3]: Daha cesur olanlarınız için örüntülü eşlemeyle ilgili daha kapsamlı bir açıklama [şuradan](http://www.cs.auckland.ac.nz/references/haskell/haskell-intro-html/patterns.html) okunabilir.\n\n[^fn-4]: `squareEvenSum''` fonksiyonunun diğer ikisinden daha verimli olduğuna dikkat edin. `(.)` fonksiyonunun sırası önemlidir.\n\n[^fn-5]: Ki kendisi JavaScript'te JSON bulunduran bir karakter dizisi üzerinde `eval` çalıştırmaya çok benzer. (Çevirmen notu: `JSON.parse` daha iyi çözüm olabilir.)\n\n[^fn-6]: Bu kurala bazı güvenli olmayan istisnalar da var. Ama belki hata ayıklama amacı dışında hiçbir gerçek uygulamada böyle bir kullanım görmezsiniz.\n\n[^fn-7]: Merak edenler için: gerçek tip şöyle: `data IO a = IO {unIO :: State# RealWorld -> (# State# RealWorld, a #)}`. `#` işareti optimizasyonla ilgili, ve ben örneğimde alan yerlerini değiştirdim. Ama ana fikir bu.\n\n[^fn-8]: Tabii ki alışana ve tamamen anlayana kadar çalışmanız gerekiyor. Ama bu yönde büyük bir adım attınız bile.\n"
  }
]