Saf Fonksiyonlar (Pure Functions)

Fonksiyonel programlamanın temel prensiplerinden birisi de kodlarını teknik anlamda saf fonksiyonlar üzerine inşa etmektir. Belirli bir girdinin tek etkisi oluşturduğu çıktı olup başka bir yan etkisi bulunmamaktadır.

object Math{
    def +(x:Int, y:Int) = x+y
}

def main(args: Array[String]): Unit = {
    println(Math.+(2,2)) //Geriye toplamları döndürür.
}

Yukarı da kod örneğine bakacak olursak fonksiyona geçilen parametreler herhangi bir dış etkiye marus kalmamış ve değerleri değiştirilmemiştir. Yani bir işleme tabi tutulmuş ve geriye buna bağlı olarak sonuç döndürülmüştür. Bu gibi fonksiyonlara yan etkisi olmayan saf fonksiyonlar diyoruz.

Ek olarak fonksiyon isimlerinde operatör işaretleri kullanabiliyorsunuz bu scala nın size sunmuş olduğu bir esneklik gibi düşünebiliriz.

Ayrıca saf fonksiyonları test etmek saf olmayan (impure) fonksiyonlara göre daha kolay ve sade bir şekilde yapılmaktadır. Sizi çok fazla durum (case) ile uğraştırmaz ve basite indirgemeye iten bir kullanım söz konusudur.

Saf fonksiyonların saf olmayan fonksiyonlara göre hata ayıklanması daha kolaydır, çünkü saf bir fonksiyonun çıktısı yalnızca fonksiyonun giriş parametrelerine ve algoritmasına bağlıdır. Hata ayıklamak için fonksiyonun kapsamının dışına bakmanız gerekmez.

Eğer yan etkileri de anında göz önüne alacak ve bununla birlikte bir işlem gerçekleştirilecek ise bu paradigma ya reaktif (reactive) programlama deniyor. Reaktif programlar uygulama çalışırken kod satırında ki akışı takip etmek yerine olayları takip ederler. (Event , Stream) Neyse konumuzu dağıtmadan saf fonkisyon etmenlerine devam edelim.

Referans Şeffaflığı (Referential Transparency)

Referans şeffaflığı fonksiyonel programlama da yagın olarak kullanılna bir terim kısaca bahsetmek gerekirse bir fonksiyona bir argüman verildiği zaman daima aynı çıktığı alacağımız anlamına gelir.

def plus(x:Int): Int ={
    x + 1
}

Referans şeffaf bir fonksiyon ile bir argüman göz ve beraberinde fonksiyon içerisinde ki işlevler göz önüne alındığı zaman bir fonksiyon çağırmak yerine değeri ilgili fonksiyon işlevine göre değiştirebilirsiniz. Örneğin plus fonksiyonuna 3 değeri atamak ve fonksiyondan dönen değeri beklemek yerinde değeri 4 ile değiştirebilirsiniz.

Bir başka örnek matematikden verilebilir. Matematik de bir fonksiyona verilen girdi değeri ile o fonksiyonun çıkış değeri her zaman belirli bir değere eşlenir. f(x) = x + 1 fonksiyonuna baktığımız zaman matematiksel fonksiyonlar şeffaftır diyebiliriz.

Bu kapsam fonksiyoneş programlama için önemli bir yapıdır. Çünkü referansa göre şeffaf bir fonksiyona sahip olduğunuzda ilgili fonkisyon size otomatik paralelleştirme ve önbelleğe alma kolaylığı sağlar.

Bir ifadenin, bir programın davranışını değiştirmeden değeriyle değiştirilebilmesi (diğer bir deyişle aynı girdide aynı işlevleri ve çıktıları olan bir programı üretmek) halinde, referansı şeffaftır diyebiliriz.

Birincil Sınıf Fonksiyonlar (First Class Functions)

Birincil sınıf fonksiyonlar bir nesne veya bir statik metod gibi ele alınan işlevlerdir. Bir değişkene atanabilir ve değişken üzerinden işlem yapabilirsiniz. Bu da biz geliştiricilere fonksiyonel programlama tarafından sunulmuş bir kolaylıktır.

def plus(x:Int): Int ={
    x + 1
}

def main(args: Array[String]): Unit = {
    val static : Int => Int = plus;
    println(static(1)) // 2
}

Örnekten de anlaşılacağı üzere bir fonksiyonumuz var ve bir dğeişkene atadık bu değişken üzerinden işlem yaptık. Bu nesne yönelimli programlama dan ziyade fonksiyonel programlama paradigmasında karşılaşabileceğiniz bir durum.

Bu özellik tartışılanın üzerine Haskell veya Erlang gibi tamamen fonksiyonel dillerden alınan bir yapıdır.

Yüksek Mertebeden Fonksiyonlar (High Order Functions)

En az bir fonksiyonu parametre olarak alan fonksiyonlara yüksek mertebeden fonksiyonlar denir. Scala da yüksek mertebeden fonksiyon tanımlamak mümkündür.

object Demo {
   def main(args: Array[String]) {
      println( apply( layout, 10) )
   }

   def apply(f: Int => String, v: Int) = f(v)

   def layout[A](x: A) = "[" + x.toString() + "]"
}

Yukarı da anlaşılacağı üzere apply fonksiyonuna parametre olarak layout fonksiyonu geçilmiştir.

İsimsiz Fonksiyonlar (Anonymous Functions)

Bazen bir değeri değişkene atmak yerine onu kullanılması gereken yerde direk kullanırız bazen de fonksiyon yazarken isim bulmakta zorlanırız ya da farklı etkenlerden dolayı bu gibi durumlarda fonksiyonu isimsiz bırakabiliriz. İşte Scala biz geliştiricilere böyle bir kolaylık sağlıyor.

def cube(x: Int) = x*x*x

yukarı da scala ile yazılmış basit bir küp hesaplama fonksiyonu var ve fonksiyonumuzun ismi 'cube'. Aynı fonksiyonu aşağıda isimsiz (anonymous) olarak yazdım.

(x: Int) => x*x*x

Bu nerelerde işimize yarar derseniz. Hatırlarsanız Yüksek Mertebeden Foksiyonlar (High Order Functions) en az bir fonksiyonu parametre alıyordu bu gibi durumlarda fonksiyonun adını yazmak yerine direk isimsiz bir fonksiyonu oarametre geçebilriiz. Daha efektif bir kullanım olabilir.

Değişmezlik (Immutability)

Scala collectionsları iki gruba ayırabiliriz. Bunlar; mutable ve immutable collections. Mutable collectionslar update edilebilir yada genişletilebilir. Ekleme, çıkarma vs. gibi işlemler yapılabilir. İmmutable collectionslar ise değiştirilemez, daha çok sabit olarak adlandırılır.

Scala collectionlarscala.collectionpaketi altında bulunur. Bu paket altında dascala.collection.mutableve scala.collection.immutable paketleri bulunmaktadır.

scala.collection.immutable : Bu paket altındaki collectionslar create edildikten sonra değiştirlemeyeceğini garanti eder. Farklı zamanlarda collectionsa erişilince aynı elementleri yield(ürün) eder.

scala.collection.mutable : Collectionslar üzerinde operasyonlara izin verir.

Collectionlar strict(sıkı) yada lazy(tembel) olabilir. Scala collections default olarak strict’dir.

Scala collections’da bir çok class ve trait(interface) bulunur. Mutable ve immutable collactionlar için main trait Iterable(sıralı) trait’dir.

results matching ""

    No results matching ""