fatiherikli

Fonksiyonel programlama dilleri sadece fonksiyon kullanarak program geliştirmeye olanak tanır. Ayrıca fonksiyonların istenen değeri döndürmekten başka bir görevi de olmaz. Şurada daha da açıklayıcı bir tanım bulabilirsiniz.

Python fonksiyonel bir programlama dili değildir ancak fonksiyonel programlamaya özgü bazı özellikleri desteklemektedir.

Python üzerinde fonksiyonlar birer first-class objelerdir. Bu sayede fonksiyonu istediğiniz gibi saklayabilir, başka bir fonksiyon parametresi olarak alabilir, parametreleri üzerinde oynayabilirsiniz. Python'da built-in olarak high-order functions olarak bilinen verilen fonksiyon olarak parametre alan ve olarak başka bir fonksiyon veya verdiğiniz fonksiyone özgü sonuç döndüren fonksiyonlar bulunmaktadır.

Aşağıda bir kaç tane teknik ve python'da üzerinde html kod üretebilmek için bir Internal (embedded) DSL örneği verdim.

Lambda

Lambda ile isimsiz fonksiyon (anonymous function) tanımlayabilmektesiniz. Bu size fonksiyonlarınızı çok daha kısa ve tek satırda oluşturmanıza olanak tanır.

wrap_tags = lambda x, c : '<%s>%s</%s>' % (x, c, x)  
print wrap_tags('strong', 'heey')
# <strong>heey</strong>

Bu fonksiyonu aşağıdaki gibi de yazabilirdiniz. İki fonksiyonun sonucu da aynıdır. Farkı ise Lambda ile tek satırda yazabiliyor olmanız.

def wrap_tags(x, c):
    return '<%s>%s' % (x, c, x)

Closures

Closures bir fonksiyonun içinde verilen değere göre döndürülen başka fonksiyonlardır. Yukarıdaki örneğimizde wrap_tags adında fonksiyon yazdık. Bu fonksiyon bize verdiğimiz tag'a ve text'e göre html kodu yazdırıyor. fonksiyonu aşağıdaki gibi closure olarak kullanalım.

def tag_factory(tag):
    def inner(code):
        return wrap_tags(tag, code)
    return inner

Bu fonksiyonun lambda şekli;

tag_factory = lambda tag : lambda code : wrap_tags(tag,  code)

tag_factory fonksiyonumuz tag parametresi almakta ve bu taga göre wrap_tags işlemini yaptıran bir fonksiyonun döndürmekte. Bu fonksiyonu aşağıdaki gibi kullanabiliriz.

print tag_factory('html')(
        tag_factory('head')(
            tag_factory('title')('SELAAM')
        )
      )  
# result is <html><head><title>SELAAM</title></head></html>

Partial

functools kütüphanesindeki bu araç ile bir fonksiyonu önceden belirlediğiniz parametrelerle çağırıp kullanabilirsiniz. Bu işlemin adı currying'dir. Örnek olarak yukarıdaki closure örneğini partial methodu ile gerçekleştirelim.

from functools import partial
wrap_tags = lambda x, c : '<%s>%s</%s>' % (x, c, x)  
HTML = partial(wrap_tags, 'html')
BODY = partial(wrap_tags, 'body')
HEAD = partial(wrap_tags, 'head')
STRONG = partial(wrap_gas, 'strong')  
UL = partial(wrap_tags, 'ul')
LI = partial(wrap_tags, 'li')

print HTML(        
          BODY(
              UL(
                 LI('Selamlar')
              )
          )        
      )

Reduce

Yukarıdaki örneğimizde basitçe python üzerinde html kod üretmek için mini bir Internal DSL yazdık :) Ancak bir eksiği var. Html fonksiyonları yalnız bir adet parametre alıyor. Yani yukarıdaki örnekte iki adet ya da daha fazla liste öğesi içeren bir liste çıkaramıyoruz. Bunu reduce ile aşabiliriz.

Reduce bir dizideki elemanların tümünü tek tek belirttiğiniz fonksiyona verip tüm elemanlarla ilgili bir sonuç çıkarmanızı sağlayan araçtır. Reduce'a ilk vereceğiniz parametre iki adet parametre alan bir fonksiyon, ikincisi bir liste, üçüncüsü de sonucun başlangıç (initial) değeridir. Reduce işlemi folding olarakta bilinmektedir.

Basir bir örnek yapalım;

from operator import add  
print reduce(add, range(1,10))

operator.add fonksiyonu python'daki toplama işlemidir. İki adet parametre alır ve bunları toplar. Bunu biliyoruz :) biz bu fonksiyonu reduce parametresi olarak kullanıp 1'den 10'a kadar olan sayıların toplamını aldırdık.

Şimdi DSL örneğimize geri dönelim. wrap_tags fonksiyonumuzu aşağıdaki gibi değiştirelim.

from operator import concat
wrap_tags = lambda x, *c : '<%s>%s</%s>' % (x, reduce(concat, c), x)

Çıktı aşağıdaki gibidir;

print DIV(STRONG('heey '), 'selam')
# <div><strong>heey</strong> selam</div>

operator modülündeki concat python'daki string birleştirme işleminin fonksiyonudur. Reduce üzerinde bu fonksiyonu ilk parametre, *c ile aldığımız kod listesini de ikinci parametre olarak verdik. Ve problemimiz çözüldü. Bunu string fonksiyonu olan join ile aşabilirdik ama konumuz bu değil. Maksat örnek olsun :)

Biraz daha geliştirelim. Fonksiyonuza keyword arguments olarak html tag'ının parametrelerini aldıralım. Bu işlemi yapmak için ise bir başka fonksiyonel programlama aracı olan map'i kullanacağız.

Map

İki adet parametre alır. Birinci parametre fonksiyondur. İkincisi ise listedir. Map listeki her elemanı verdiğiniz fonksiyon'dan geçirir ve size tekrar liste döndürür. Aşağıdaki örnekle daha iyi anlaşılacaktır.

print map(lambda x : x*x, range(1,10))  
# [1, 4, 9, 16, 25, 36, 49, 64, 81]

Parametre olarak verdiğimiz fonksiyon verilen sayının karesini döndürmekte. Gördüğünüz üzere 1'den 10'a kadar olan sayıların karesi liste şeklinde elimizde artık. Şimdi tekrar DSL örneğimize geçelim. Html tagları için parametre örneğini yapalım. Bu işlemi lambda yerine klasik fonksiyon ile yapalım.

def parameters(**p):
    def _build_parameters(parameter):
        key, value = parameter
        return ' %s="%s"' % (key, value)
    return reduce(concat, map(_build_parameters, p.items() ) , '')

wrap_tags = lambda x, *c, **p : '<%s%s>%s</%s>' % (x, parameters(**p), reduce(concat, c), x)

Bu fonksiyonun lambda şekli ise;

parameters = lambda **p : \
             reduce(concat,
                # build parameters from dict with mapping.
                map(lambda k: ' %s="%s"' % (k[0], k[1]) , p.items() ),
                '') # empty string for reduce initial.

Artık keyword-arguments olarak html parametreleri belirtebiliyoruz;

print DIV('selamlar', id='container', style='font-size:15px')
# <div style="font-size:15px" id="container">selamlar</div>

Html tag'ının parametreleri bize keyword-arguments olarak Dictionary şeklinde gelmekte. Biz bu dictionary objesini items metoduyla (key, value) şeklinde tuple içeren bir listeye dönüştürdük. Key parametremiz, value ise parametremizin değeri. Biz listedeki parametrelerimizi html'e uygun olacak şekilde döndürüp Reduce ile düz bir string haline getirdik.

Filter

Bu işleme DSL'de ihtiyaç duymadık ancak çok kullanışlı fonksiyonlardan bir tanesidir. Map ve Reduce'deki gibi ilk parametre fonksiyon, ikincisi de liste olacak şekilde kullanmaktasınız. Fonksiyonunuz boolean (true/false) bir değer döndürmelidir. Filter işlemi verdiğiniz bu fonksiyona göre listenizde filtreleme yapacaktır. Aşağıdaki örnekle çok daha iyi anlaşılacaktır.

print filter(lambda x : x % 2 == 0, range(1,10))
# [2, 4, 6, 8]

Bir sayının 2'ye bölünüp bölümediğini kontrol eden bir fonksiyon yazdık. Ve bu fonksiyone göre sonucu False dönenleri filtreledik.

Ve son olarak DSL örneğini tam olarak vereyim. Ancak bir şey belirtmek istiyorum;

Dikkat. Ofiste denemeyin !

Aşağıdaki örneği tamamen fantazi olsun diye veriyorum :) Zira aşağıdaki gibi partial'ı partial olarak çağıran, lambda kullanıcam diye ortaya anlaşılmaz karman çorman bir kod çıkaran, yerden tasarruf olsun diye değişkenleri packing şeklinde tanımlayan bir iş arkadaşım olsa herhalde boğardım ben. Fonksiyonlar arasında hoplayıp zıplamak ne kadar eğlenceli olsa da abartmamak gerekir. pep-8'e ve diğer kod standartlara küfür niyetinde bir kod yazdık :)

# -*- coding:utf-8 -*-
from functools import partial
from operator import concat

parameters = lambda **p : \
             reduce(concat,
                # build parameters from dict with mapping.
                map(lambda k: ' %s="%s"' % (k[0].replace('_',''), k[1]) , p.items() ),
                '') # empty string for reduce initial.

wrap_tags = lambda x, *c, **p : \
            '<%s%s>%s</%s>' % (
                x, # open tags
                parameters(**p), # tag parameters
                reduce(concat, c), # content
                x)  # close tags

HTML, HEAD, TITLE, BODY, H1, UL, LI, FOOTER, DIV = map(\        
    partial(partial, wrap_tags),
    ['html', 'head', 'title', 'body', 'h1', 'ul', 'li', 'footer', 'div']
)

print HTML(
        HEAD(
            TITLE('Python üzerinde fonksiyonel programlama')
        ),
        BODY(
            H1('Fonksiyel programlama nedir ?', style="margin:0px;", id="title"),
            UL(
                LI('Lambda', _class="first"),
                LI('High-order Functions'),
                LI('Functions as First-class Objects'),
                LI('Closures'),
                LI('Currying', _class="last"),
            )
        ),
        FOOTER(
            DIV("Her hakkı saklıdır.", id="footer")
        )
     )

Evet, fonksiyonel programlama araçları sayesinde tüm kodumuzda sadece iki adet ismi olan fonksiyon tanımladık. Fonksiyonel programlama dillerindeki esneklik olmasa da python'da gayet tatlı bir şey çıkardık :)

Aşağıdaki bağlantıları da incelemenizi tavsiye ederim.

[http://c2.com/cgi/wiki?FunctionalProgramming

](http://c2.com/cgi/wiki?FunctionalProgramming)[http://en.wikipedia.org/wiki/ Functional_programming

](http://en.wikipedia.org/wiki/Functional_programming)[http://www.slideshare. net/adambyrtek/functional-programming-with- python-516744

](http://www.slideshare.net/adambyrtek/functional-programming-with- python-516744)[http://www.slideshare.net/newmedio/introduction-to-functional- programming

](http://www.slideshare.net/newmedio/introduction-to-functional- programming)[http://burcudogan.com/2009/03/08/functional-programing-for- beginners/](http://burcudogan.com/2009/03/08/functional-programing-for- beginners/)

comments powered by Disqus