Bu aralar monadların ne olduğunu anlamaya çalışıyorum. Henüz kafamda çok boşluk var ama en azından şimdiye kadar öğrendiklerimi pekiştirmek adına not almak iyi bir fikir olabilir.
Bir yapının monad olması için bir 2 tane fonksyonu olması gerekir.
- m-bind fonksyonu : bir değer ve bu değerleri işleyecek bir fonksyon alır.
- m-result fonksyonu : Geriye monadic bir değer döndürmesi gerekiyor (ileride açıklanacak).
Monad anladığım kadarıyla ardışıl olarak yapılması gereken işlemleri sistematize ve abstract etmek için düşünülmüş bir yöntem. Arama motorlarında “monad” aratınca genelde Haskell dili karşımıza çıksa da bu yapıları diğer dillere uygulamak mümkün.
Çoğu incelediğim örneklerde genelde clojure’ın let yapısı örnek olarak veriliyor. Örneğin :
1 2 3 4 5 6 |
|
Clojure ile pek ilgilenmeyenler için açıklayacak olursak. Öncelikle a değişkenine 12 değeri veriliyor, daha sonra b değişkenine a ‘nın bir fazlası veriliyor, en sonunda da 2 değer çarpılıp sonuç geri veriliyor.
Bu tür bir yapıyı let olmadan yapmaya çalışsak nasıl olur ?
1 2 3 4 5 6 7 8 |
|
Öncelikle yukarıdaki örnek biraz karmaşık görünebilir, biraz zaman verin gözünüz alışacaktır. Bu anlamda baktığımızda let işimizi oldukça kolaylaştırıyor gerçekten. Aslında let bir karar verme mekanizması gibi. [a 12] ifadesinde 12’yi alıp drek olarak a’ya atadı, bunun aksine 12 ile başka birşey de yapabilirdi. Örneğin bir listeye koymak gibi veya daha farklı işlemler. Pseudocode olarak şöyle görünebilir. Belki javascript syntaxı daha iyi gösterebilir :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Buradaki mbind ve mresult fonksyonları oldukça önemli. Bu 2 fonksyon monadların oluşması için gereken ana yapıları teşkil ediyor. Bir de monadların kuralları var ama kendi monadınızı yazmadığınız sürece pek gerekli olmuyorlar(zaten henüz açıklayacak kadar da bilmiyorum :) ).
Bir monadın diğerinden farkı bu mbind ve mresult fonksyonlarının implementasyonundan kaynaklanıyor. Yukarıda gösterdiğim monad identity monad diye geçiyor. Fakat hangi monad olursa olsun üzerinde yapılan işlemler aynı oluyor. Yani üzerinde sürekli m-bind fonksyonu çağırılıyor ve en sonunda m-result fonksyonu çağırılıp sonuç geriye döndürülüyor. Bu kısmın anlaşılması oldukça önemli.
Şimdi bir diğer monada bakalım maybe monadı. Maybe monadı, art arda yapılması gereken işlemlerden dönen sonucun geçersiz olması problemini çözüyor. Örnek olarak şöyle bir kaç işlemimiz olsun :
1 2 3 |
|
Yukarıdaki kodda şöyle bir sıkıntı var. Eğer dönen değerlerden herhangi biri null ise sonucu işleyen fonksyonun kendi içinde bunu kontrol etmesi veya bunu biraraya getiren kodun buna bakması gerekiyor. Yani :
1 2 3 4 5 6 7 |
|
Herhangi bir yerde bunu unutacak olursak, undefined hatası alacağız. Maybe monadı ile bu işlemi çözebiliriz :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
Yukarıda mbind fonksyonun içeiriğini biraz değiştirdik. Eğer kendisine geçirilen değer null ise (geçersiz) işlemi durduruyoruz. Şimdi yukarıdaki kodu test edelim:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
Görüldüğü gibi yukarıda bahsettiğim undefined hatalarından bu şekilde arınmış olduk. İlk örnekteki akışa uyduracak olursak :
1 2 3 4 5 6 7 8 9 |
|
Bu örnekte de yine not edilmesi gereken ana akışın aynı olduğudur(mbind zinciri ve en sonunda mresult).
Şimdi mresult’un da içinde olduğu başka bir örneğe bakalım. Clojure’da for comprehension yapısı for ile sağlanıyor. Örneğin :
1 2 3 4 5 |
|
Yukarıdaki yapı iç içe girmiş for dongüsünü temsil ediyor. İçteki b dongüsü dıştaki a dongüsünden hızlı gidiyor. Buna benzer bir olayı monadlarla nasıl gerçekleştiririz ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
|
Yukarıdaki örnek biraz complex görünebilir, ama aslında oldukça kolay(biraz inceledikten sonra). Burada mresult geriye bir liste döndürüyor. Yukarıdaki örneklerde aldığı değeri aynı şekilde geri döndürüyordu, burada durum biraz daha farklı. Bu noktada biraz tanım yapmak gerekiyor.
- mresult tarafından dönen değer bizim monad değerimiz oluyor (monad value).
- mbind‘in her zaman monad değeri döndürmesi gerekir. maybe monad değerin aynısını döndürüyordu, list monadı geriye liste döndürdü.
- mbind fonksyonunun ilk parametresi de monad değeri olmak zorunda. Kısacası mbind monad alıp monad veriyor geriye. Bunun faydası, bu tür yapıların iç içe (chain) geçirilip tek fonksyon gibi kullanılıyor olması (başka bir blog yazısı).
Girdinin fazla uzamaması açısından burada kesiyorum. Bir diğer blog yazısında da state monadı hakkında öğrendiklerimi paylaşacağım.
İlgilenenler için bulduğum monad kaynakları :
Videolar :
Diğer :