Fonksiyonel Programlama Notları ve JavaScript
26 Oct 2013Bu yazıda yazdıklarım araştırmalardan edindiğim notları içeriyor.
Fonksiyonel Programlama
Fonksiyonel programlama işin daha fazla matematiğe kaydığı bir programlama türü. OOP’de ne kadar nesne varsa, FP’de o kadar matematik var. “Fonksiyonel programlamadaki fonksiyonlar, aynı matematikteki fonksiyonlar gibi:
f(x) = 2*x + 5
dediğimizde bunun her zaman return
eden bir fonksiyon olduğunu biliriz.
Bu işlemin JavaScript versiyonu.
Fonksiyonel programlamanın en büyük özelliklerinden birisi de diğer bir çok imparative dile göre, fonskiyonların prosedürden daha çok bir veri türü olması. Bu fonksiyonlara farklı bir bakış açısı getiriyor.
Mutable ve Immutable veri türleriyle ilgili yazıya buradan ulaşabilirsiniz
Saf Fonksiyonlar ve Yan Etki
“Global değişken” konusu biraz FP’nin mantığına aykırı. Bu anlamda OOP ile aralarında epey farklılık olduğu aşikar. Eğer bir fonksiyon kendisi kapsamındaki dışındaki bir değeri değiştiriyorsa veya etkiliyorsa buna yan etki (side-effect) deniyor.
Mesela bir fonksiyonun bir dosyaya yazması veya konsola çıktı vermesi yan etki sayılabilir.
Mesela bu yan etkiye sahip bir fonksiyon. Çünkü y
değişkeni fonksiyonun bir parametresi veya sahip olduğu bir değişken değil.
void fonksiyon kavramı, FP’de tamamen yan etki. Çünkü bir fonksiyon bir şey döndürmüyorsa kesinlikle yan etki yapıyordur, veya işe yaramıyordur.
Bu void bir fonksiyon ve hiç bir dönüş değeri yok, yan etki yok ama kullanışsız.
Bu da bir void fonksiyon, fakat yan etki yaratmış.
Her iki açıdan da void fonksiyon FP için mantıksız.
Monad
Fakat yazdığımız bir çok kodda bu tarz yan etkileri yapma zorunluluğu hissediyoruz. FP’de bunun için Monad denilen bir kavram getiriyorlar. Monadlar kısaca yan etki yaratmadan yan etki kullanmamız gereken durumlarla başa çıkmamız için geliştirilmiş bir kavram.
Fonksiyonlar kendi ihtiyacı olan yan etkileri parametre olarak alıp müdahale ediyorlar, böylece yan etki yaratmadan aynı işlemleri yapabiliyoruz. Yani global state’de bir şey tutmadan bir state’i taşıyabiliyoruz.
diye bir fonksiyonumuz olduğunu varsayalım;
diye de başka bir fonksiyonumuz var;
y
nin taşımamız gereken global bir state olduğunu düşünelim;
Bu durumu biraz irdeleyelim;
görüldüğü gibi y
değerinin state’ini taşıdık, ve yanetki kullanmadık.
Bu konuyu anlamamda ssg’nin ekşisozlük’te yazdığı bu entry epey faydalı oldu. Şimdi onun verdiği örneği JavaScript ile yazalım;
Normalde yan etki kullanarak bir toplama fonksiyonu yazalım;
Şimdi bu yanetkiye sahip fonksiyonu yan etkisiz hale getirelim;
Tabii bu noktada çok fazla kafa karıştıran şey var, bunları iyice anlamak gerekiyor ve ben de şu an henüz öğrenme aşamasındayım :)
Kompozisyon
Biraz önce birer f
ve g
fonksiyonu tanımlamıştık;
Fonksiyonel programlamada farklı fonksiyonları compose
ederek yeni bir fonksiyon elde edebiliyorsunuz, yine aynı matematikteki gibi;
g o f
fonksiyonu g
ve f
fonksiyonunun bir kompozisyonu olmuş oldu.
Özyineleme (Recursion) ve Döngüler
Bu tarz Türkçeleştirmeye karşıyım ama kullanayım dedim. :) Fonksiyonel programlamada yan etki sevilmediği için for
döngüsü veya while
gibi imparatif deyimler çok mantığa uymaz. Dolayısıyla bu tarz döngüleri recursion
ile yaratırız.
Bir faktöriyel fonksiyonunu imparative şekilde yazalım;
Şimdi bunu recursion kullanarak yazalım;
Böylece aynı işlemi fonksiyonel olarak yazmış olduk.
JavaScript’te Fonksiyonel Programlama
Fonksiyonların first-class olması (yani Number, String gibi üst seviye olması) JavaScript’le fonksiyonel programlama yapılabilmesine oldukça fayda sağlıyor. JavaScript’te sıkça kullandığımız anonim fonksiyon kavramı, first-class fonksiyonlardır. Fonksiyonun oluşturulduktan sonra o anda/daha sonra çalıştırılabilmesi, hatta o anda oluşturulup çalıştırılıp çağrılabilmesini sağlar. Bu noktada “fonksiyon kapsamı” programın genelinin bir parçası olur ve problemlerin çözümünde farklı bir bakış açısı getirir. Ayrıca fonksiyonların aynı veri türleri gibi başka bir fonksiyon tarafından dönmesi de muhtemel hale gelir.
Aynı zamanda currying, binding gibi fonksiyonel işlemleri de yapabilir hale gelirsiniz.
Mesela:
Eloquent JavaScript (Marijn Haverbeke) isimli kitaptan bir alıntı yapacağım, örneği biraz değiştirdim, bu örnekte JavaScript’in fonksiyonel olarak nasıl kullanılacağına dair bir fikir edinebiliyoruz;
Burada hiçbir yan etki yaratmadan toplama fonksiyonu oluşturduk:
Neyse ki, JavaScript zaten reduce
fonksiyonunu bize sağlıyor, bu yüzden tekrar implemente etmemize gerek yok. Dolayısıyla, sum
fonksiyonunu JavaScript’te daha hızlı ve kolay şu şekilde hazırlayabiliriz:
veya add
fonksiyonunu da anonim hale getirelim;
map
, reduce
ile Fonksiyonel Faktöriyel Örneği
JavaScript’te Array
kullanarak bir sequence
oluşturabilirsiniz.
Dolayısıyla
şeklinde bir değer oluşturacaktır.
şeklinde bir değer oluşturur. Yani hızlıca istenilen uzunlukta bir dizi oluşturmak JavaScript’te fonksiyonel olarak çok kolay.
Şimdi de bu fonksiyonu faktöriyel hesaplamak için kullanmaya çalışalım;
fonksiyonel olarak bir aralık oluşturduk, daha sonra bu aralıktan çıkan her değeri map
ile 1 artırdık ve reduce
ile çarparak faktöriyel hesaplamış olduk.
Sonuç
Volkan Özçelik’in Facebook’ta bu posta yazdığı yorum da çok güzel açıkçası:
En basitinden promises bir fonsiyonel programlama örneğidir. (Promise aslında “monad” fonksiyonel yapısının JavaScript’e uyarlanmış halidir). Monad’lar da “adana dürüm”un programlama dünyasında yansımasıdır (bkz: http://chrisdone.com/posts/monads-are-burritos). Onun dışında Underscore, jQuery ve pek çok diğer kütüphane fonksiyonel programlamayı kendi içinde kullanır. En basitinden ajax çağrılarında kullandığımız “callback”ler aslında “continuation passing style” dediğimiz fonksiyonel yapının bir uygulamasıdır. Daha da basiti, “fonksiyon” gördüğünüz ve fonksiyonların birinci sınıf vatandaş olduğu her dilde, bilerek ya da bilmeyerek fonsiyonel programlama yapıyorsunuzdur. Daha kısa cevap: Evet genel olarak matematiksel ve “state” içermeyen işlemlerde kullanılır fonsksiyonel programlama; bununla birlikte, Haskell gibi “state” içeren dosya okuma / IO işlemleri vb.’ni “monad”lar yardımıyla fonksiyonel dünyaya map’leyip fonksiyonel programala yapan diller de var. Fonksiyonel diller “purely functional” ve “functional with side effects” diller olmak üzere ikiye ayrılır.
Fonksiyonel programlama problem çözümüne yeni bir bakış açısı katmakla beraber, günlük sorunlarımızı nasıl çözebileceğimiz konusunda da fikir veriyor. Tabii multi-paradigma gözüyle bakarak iyi yönlerini almaya çalışmakta fayda var.
Gördüğünüz hataları yorum olarak yazarsanız çok mutlu olurum. :)