Kotlin: Lambdas & Higher-Order Functions

Recep Fırıncıoğlu
4 min readJun 1, 2021

--

Higher-order ya da birçok kişiye daha tanıdık gelecek olan ismiyle yüksek dereceden/mertebeden fonksiyonlar.

“Fonksiyonlar” başlıklı önceki yazımda Kotlin’de fonksiyonların first class citizen olduğundan bahsetmiştim. Yani bir değişkene değer olarak atanabiliyor, bir fonksiyona parametre olarak verilebiliyor ya da fonksiyonların geri dönüş değeri olabiliyorlar. Higher order functions dediğimiz yapılar en basit tabiri ile bir fonksiyona parametre olarak verilen fonksiyonlardır. Birçokları için “o eski zamanlardan” olan, lise matematik derslerinden f(g(x)), f(g(x)+2), g(3f(x)+4) şeklinde kullandığımız yapıları anımsayın. Özünde yapılan şey aslında bundan farklı değil.

Şimdi higher-order fonksiyonlardan önce lambda diye bir kavramdan bahsedelim. Bunlar diğer dillerde anonymous functions, function literals ya da benzer şekilde isimlendirilen ve Kotlin’de lambda denilen yapılardır. Fonksiyonların bir değişkene değer olarak atanabileceğinden bahsetmiştik. Bu kullanıma Kotlin’de expression deniliyor ve lambda ise tam olarak burada devreye giriyor. Lambda için, fonksiyonu oluşturan expression diyebiliriz.

Lambda yapısı sayesinde bir isim ile fonksiyon tanımlamak yerine, ismi olmayan bir fonksiyon tanımlayabiliyoruz. Aşağıdaki kod bloğunda en basit hali ile bir lambda fonksiyonun nasıl yazıldığını görebilir, hemen altındaki sayHello() fonksiyonu ile kıyaslayabilirsiniz. Eminim fark edeceksiniz, yapı süslü parantezlerin sonuna koyulan normal parantezlerden ibaret.

{whatever_you_want} ()

Lambdamızı oluşturup hiçbir yerde kullanmamak pek verimli değil elbette. Peki ne mi yapabiliriz? En basiti ile başlayalım, örneğin bir değişkene lambda atayabiliriz. Hemen alttaki kod bloğunda, süslü parantezler içerisinde lambdamızı görebilirsiniz. Bu şekilde bir kullanımla değişkenimizi normal bir fonksiyon gibi çağırabiliriz.

Şimdi gelelim lambdaların bir başka özelliğine, lambdalar tıpkı normal fonksiyonlar gibi argümanlar alabilirler. Aşağıda görüldüğü gibi lambdaExpression isimli değişkeni tanımlarken lambdanın expression kullanımından faydalandım. lambdaExpression isimli değişkene tanımladığım lambda, arg1 ve arg2 adında Int tipinde iki adet veri alıyor. Ardından bu iki sayıyı toplayıp println() ile konsola yazdırıyorum. Bir alt satırda ise normal bir fonksiyon gibi çağırılarak kullanıldığını görebilirsiniz.

Artık şu meşhur higher-order fonksiyonlara gelebiliriz. Kod bloklarına geçmeden önce ne yapacağımdan kısaca bahsedeyim. Verilen iki sayıyı toplayan ve çarpan iki ayrı fonksiyon yazacağız. Ardından başka bir fonksiyona bu fonksiyonu bir parametre olarak gönderip yapmak istediğimiz işlemi seçebileceğimiz bir yapı oluşturacağz.

Öncelikle temel fonksiyonlarımızı oluşturalım. Fonksiyonlarımızı tanımlayıp main() fonksiyonumuzda çağırdığımızda aşağıdaki çıktıyı elde edeceğiz. Buraya kadar her şey bildiğimiz gibi.

Şimdi ise mathOperation isimli bir fonksiyon tanımlayıp bu fonksiyona ikisi Int tipinde biri ise fonksiyon olan toplamda üç adet parametre yazacağız. Ardından main() fonksiyonuma dönüp bu fonksiyonu çağırıyorum. Bu fonksiyonu çağırırken mathOperation fonksiyonunun beklediği parametrelerin üçüncüsünün bir fonksiyon olduğunu görebilirsiniz. Bu arada Intellij IDEA’nın bu yardımı için CTRL+P kısayolunu kullanabilirsiniz.

Toplama işlemini yaptığımız fonksiyonu üçüncü parametremiz olarak girerken “ ::addition şeklinde, önünde iki adet iki nokta işereti ile ekliyoruz. Aynı kullanımı çarpma işlemi için hazırlamış olduğum fonksiyon için de üçüncü parametreme “ ::multiply ” yazıyorum. Bu kullanıma fonksiyon referansı deniliyor.

Kod bloğu ve çıktısı aşağıdaki şekilde. main() fonksiyonundan yukarıda bahsettiğimden, burada mathOperator fonksiyonundan bahsedeceğim. İlk iki parametremiz Int tipinde veri bekliyor, zaten normal fonksiyonlardan da tanıdık gelecektir. Üçüncü parametre olarak fonksiyonu verirken ilk önce fonksiyonun adı ve iki nokta ardından parantezler içinde bu fonksiyonun alacağı parametreleri belirtiyoruz. Ok işaretinden sonra da geri dönüş tipini belirtiyoruz. Ardından expression ifade kullanarak fonksiyonumuzu çağırıyoruz.

Burada dikkat edilmesi gereken şey main() fonksiyonu içerisinde mathOperation fonksiyonunu çağırdığımızda addition yada multiply fonksiyonlarının doğrudan çalışmadığı, mathOperation fonksiyonunun gövdesine gidildiğinde çağırıldığıdır.

Son bir örnekle higher-order fonksiyonların en sık kullanım şekillerinden birinedeğineceğim. Öcelikle kod bloğunda ne yaptığımdan kısaca bahsedeyim. Tanımlanan number1 ve number2 isimli iki değişkenimiz var ve bunların değerleri 10'dan büyükse sayının 10'a bölümünden kalanı, 10'dan küçük olduğu takdirde ise sayının kendisini yazdıran isGreater() adında bir fonksiyonumuz var. Bu fonksiyon bahsettiğim değerleri yazdırıyor fakat sayının 10'dan büyük olması durumunda 10'a bölümünden kalan değeri elde etmek başka bir fonksiyonun işi. Her fonksiyonun tek bir işi olmalı hatırlatmasını da burda tekrar yapmak yerinde olacaktır.

isGreater() fonksiyonuna yakından bakacak olursak, beklediği ilk parametrenin Int tipinde bir sayı olduğunu ve bu fonksiyon içinde bunun number olarak isimlendirildiğini , ikinci parametrenin ise bir higher-order fonksiyon olduğunu görüyoruz. Bu higher-order fonksiyon, “functionBlock” olarak isimlendirilmiş ve “initNumber” adında Int tipinde bir parametre beklerken yine Int tipinde bir geri dönüş değeri var.

fun isGreater(number: Int, functionBlock:(initNumber: Int)->Int) {
//some-awesome-codes
}

Yine dikkat edilmesi gereken nokta yukarıda da bahsettiğim gibi higher-order fonksiyonunun gövdesi, isGreater() fonksiyonu main() fonksiyonu içerisinde çağırıldığında değil, isGreater() fonksiyonunun gövdesinde functionBlock() fonksiyonunun çağırılmasıyla çalıştırılmakta.

Bu yapıyla ilk defa karşılaşan birçok kişinin kafasının karıştığını görebiliyor, kendimden de biliyorum. Bu sebeple olabildiğince basit tutmaya ve gerektiğinde, “Nasıldı ya ?” dediğiniz anlarda açıp bakabileceğiniz bir kaynak sunmaya çalıştım. Konu ile ilgili dokümantasyon sayfasına ait bağlantıyı da aşağıya ekliyorum. Faydalı olması dileğiyle.

--

--