Common Lisp ve Bir Optimizasyon Tekniği: Memoization

0
FZ
"Memoization" tabiri bilgisayar bilimlerinde ilk kez Donald Michie'nin 1968 yılında Nature dergisinde yayımlanan Memo functions and machine learning (Memo fonksiyonları ve makina öğrenimi) makalesi ile gündeme gelmiştir.

Memoization tekniği bir fonksiyonu hesaplarken önceden hesaplanmış değerleri hesaplamadan kullanmak, dolayısı ile işlemi hızlandırmak olarak tarif edilebilir. Sözcük olarak "memorization"ı yani "ezberleme" eylemini çağrıştırmakla birlikte daha genel bir anlamı kapsamaktadır.

Programlama dilinden bağımsız olmakla birlikte, bu yazıda "memoization" tekniğinin Common Lisp'te nasıl kullanılacağına bakacağız. Bunun için Peter Norvig'in PAIP kitabı ana eksenimizi oluşturacak.

Common Lisp ile Basit "Memoization" Örneği


(defun fib (n)
  "Fibonacci dizisindeki n. sayiyi hesaplar."
    (if (<= n 2) 1
          (+ (fib (- n 1)) (fib (- n 2)))))

Özyineli bu fonksiyonla ile ilgili temel sıkıntımız aynı hesaplamaları tekrar tekra yapıyor oluşu. Hemen bir örnek vermek gerekirse, yukarıdaki fonksiyonu Emacs+SLIME geliştirme ortamımızda yazdıktan sonra trace ile neyi nasıl yaptığını bir izleyelim:

CL-USER> (fib 5)
5

CL-USER> (trace fib)
(FIB)

CL-USER> (fib 5)
  0: (FIB 5)
    1: (FIB 4)
      2: (FIB 3)
        3: (FIB 2)
        3: FIB returned 1
        3: (FIB 1)
        3: FIB returned 1
      2: FIB returned 2
      2: (FIB 2)
      2: FIB returned 1
    1: FIB returned 3
    1: (FIB 3)
      2: (FIB 2)
      2: FIB returned 1
      2: (FIB 1)
      2: FIB returned 1
    1: FIB returned 2
  0: FIB returned 5
5

Yukarıdaki gibi bir durumla karşılaşmamızın sebebi (fib 5)'in hesaplanması için (fib 4) ve (fib 3)'ün hesaplanması ve (fib 4) için ise yine (fib 3) ve... sanırım problemin ne olduğu artık aşikardır.

Bu durumu iyileştirebilir miyiz? İlk akla gelen şey fonksiyona müdahale edip bunu biraz daha hızlandırmaktır ama bunun yerine fonksiyona hiç dokunmasak da onun yerine otomatik olarak herhangi bir fonksiyonu "memoized" hale getirebilecek bir yapı kursak nasıl olur? Common Lisp programcıları dinamik bir programlama dili ve yüksek dereceden fonksiyonlarla çalıştıkları için genellikle ikinci yolu tercih ederler, bu onlara daha "doğal" görünür.

Şöyle düşünelim, "memo" diye bir fonksiyonumuz olsa ve girdi olarak bir fonksiyon alsa ve çıktı olarak da aynı şeyi hesaplayan ama aynı şeyleri sürekli hesaplama derdinden kurtulmuş bir fonksiyon döndürse nasıl olur?


(defun memo (fn)
  "fn fonksiyonunun memo-fonksiyonunu döndür."
  (let ((table (make-hash-table)))
    #'(lambda (x)
    (multiple-value-bind (val found-p)
	(gethash x table)
      (if found-p
	  val
	  (setf (gethash x table) (funcall fn x)))))))

Yukarıdaki fonksiyonu özet olarak açıklamak gerekirse, önce bir "hash" tablosu oluşturuyor "table" isimli bir yerel değişken de bunu tutuyor, ardından da fonksiyonun asıl kısmı geliyor, lambda kullanılarak bir fonksiyon oluşturma kısmı. Öyle bir fonksiyon ki tek bir parametre alıyor, x parametresi ve sonra da yaptığı şey, (gethash x table) fonksiyonu ile söz konusu x'in yukarıda tanımlanmış olan "hash" tablosunda mevcut olup olmadığına bakmak.

Burada multiple-value-bind kullanılmasının sebebi gethash fonksiyonunu iki değer döndürmesi (evet, Lispçiler bir fonksiyon aynı anda birden fazla değer döndürünce şaşırmazlar ;-), yani x tabloda mevcut ve değeri nil olabilir, yahut x tabloda bulunmuyor olabilir, bu yüzden yine nil dönmüş olabilir. Bu ikisini birbirinden ayırt edebilmek için gethash bir de bunu belirten bir değer döndürmektedir ve biz de bunu found-p ile yakalamaktayız.

Bu açıklamadan sonra devam edelim: basit bir if yapısı ile, eğer x tabloda bulunmuş ise bulunan değeri, bulunmadı ise de hesaplanmış değeri döndüren bir fonksiyon döndürüyor ve lambda ifademizi tamamlamış oluyoruz. Hesaplanmış değeri döndürüyoruz derken, bu kısma dikkat çünkü aynı anda bunu (setf ...) ile table isimli "hash" tablosunun x ile ilişkilendirilmiş kısmına yazıyoruz, böylece bir sonraki hesapta bu aşamada hesaplamak zorunda kaldığımız x ile ilgili değeri doğrudan tablodan çekebilir hale gelmiş oluyoruz.

Bir soru (9 puan): En başta, table isimli hash tablosu değişkeninin (let ...) ile tanımlanan yerel bir değişken olduğunu belirtmiştik, o halde nasıl oluyorda bu yerel değişken (yani global olmayan), bu yerel "hash" tablosu tekrar tekrar çağrıldığında önceki değerleri koruyabiliyor? (ipucu: bkz. "closure".)

Artık elimizde kendisine bir fonksiyon geçirebileceğimiz ve karşılığında da "memo edilmiş" (memolanmış?) bir fonksiyon alabileceğimiz memo fonksiyonumuz hazır. Hemen küçük bir deneme yapalım:

CL-USER> (setf memo-fib (memo #'fib))
#<CLOSURE (LAMBDA (X)) {9DA0125}>

(Bazı uyarı mesajları ile karşılaşabilirsiniz ama bunlar şimdilik önemli değil, görmezden gelebilirsiniz. Ayrıca #' notasyonunun açıklamasını da hatırlamakta fayda var!)

Şimdi de (memo #'fib) ile üretip sonra da setf ile memo-fib'e yerleştirdiğimiz bu fonksiyonu bir çağırıp ne yaptığını izleyelim:

CL-USER> (funcall memo-fib 3)
 0: (FIB 3)
    1: (FIB 2)
    1: FIB returned 1
    1: (FIB 1)
    1: FIB returned 1
  0: FIB returned 2
2

CL-USER> (funcall memo-fib 3)
2
CL-USER> (funcall memo-fib 3)
2
Görüldüğü gibi memo-fib fonksiyonu bir kez 3 parametresi ile çağrıldıktan sonra, 2., 3., ... n. çağrılışında artık hesap yapmak yerine doğrudan "öğrenmiş" olduğu yani "memoized" değeri döndürerek optimizasyon sağlamış oluyor.İşimiz bitti mi? Hayır. Maalesef henüz ideal duruma varmış değiliz; dikkat edilecek olursa yukarıdaki "trace"te, (fib 3) için (fib 2) iki kere hesaplanıyor? Bunun sebebi nedir? Sebep şu: Özyineli olarak çağrılan fib fonksiyonunun kendisine herhangi bir müdahalede bulunmadık, dolayısı ile onun içindeki özyineleme, kendi kendini çağırması durumu "memoization"dan faydalanmıyor. Başka bir deyişle "memoized" olan fonksiyon fib değil memo-fib isimli yeni yaratılmış fonksiyon. Öyle bir fonksiyonumuz olsa ki, aldığı fonksiyonu değiştirip doğrudan onu memo fonksiyon hale getirse nasıl olur?

(defun memoize (fn-name)
  "fn-name'in global tanimini 'memoized' versiyonla degistir."
  (setf (symbol-function fn-name) (memo (symbol-function fn-name))))

Common Lisp'in yüksek dereceden fonksiyon kullanımı konusunda bir adım daha ileri gittik, yukarıdaki memoize fonksiyonu aldığı herhangi bir fonksiyonunun kendisini değiştiriyor, işin püf noktası ise tahmin edebileceğiniz gibi symbol-function.

Şimdi bu fib'in iki halini kıyaslamak için küçük bir deneme yapalım:


CL-USER> (fib 5)
  0: (FIB 5)
    1: (FIB 4)
      2: (FIB 3)
        3: (FIB 2)
        3: FIB returned 1
        3: (FIB 1)
        3: FIB returned 1
      2: FIB returned 2
      2: (FIB 2)
      2: FIB returned 1
    1: FIB returned 3
    1: (FIB 3)
      2: (FIB 2)
      2: FIB returned 1
      2: (FIB 1)
      2: FIB returned 1
    1: FIB returned 2
  0: FIB returned 5
5

Hemen ardından fib fonksiyonunu "memoized" hale getirelim:

CL-USER> (memoize 'fib)
#<CLOSURE (LAMBDA (X)) {9059C5D}>

CL-USER> (fib 5)
  0: (FIB 5)
    1: (FIB 4)
      2: (FIB 3)
        3: (FIB 2)
        3: FIB returned 1
        3: (FIB 1)
        3: FIB returned 1
      2: FIB returned 2
    1: FIB returned 3
  0: FIB returned 5
5

CL-USER> (fib 5)
5

CL-USER> (fib 6)
  0: (FIB 6)
  0: FIB returned 8
8

CL-USER> (fib 9)
  0: (FIB 9)
    1: (FIB 8)
      2: (FIB 7)
      2: FIB returned 13
    1: FIB returned 21
  0: FIB returned 34
34

CL-USER> (fib 7)
13

Görüldüğü gibi, artık gereksiz herhangi bir hesaplama yapılması söz konusu değil!

Artık elimizde epey işlevsel bir memoize fonksiyonu var ancak eğer, söz gelimi fib fonksiyonunun kendisinde bir değişiklik yaparsak bunu tekrar "memoized" hale getirmemiz için etkileşimli Lisp ortamında yine (memoize 'fib) yazmamız gerekiyor. Bunun yerine daha fonksiyonu en baştan yazarken memoize içine yazabileceğimiz ve böylece her derlenişinde otomatik olarak "memoized" hale getirilmesini sağlayabileceğimiz gibi:

(memoize 
  (defun f (x) ...)
 )


bunu yapmak yerine Common Lisp'in en güçlü özelliklerinden biri olan makrolardan da faydalanabiliriz (lütfen diğer dillerdeki primitif makro kavramları ile karıştırmayalım! ;-):

(defmacro defun-memo (fn args &body body)
  "'memoized' fonksiyon tanimlama makrosu."
  `(memoize (defun ,fn ,args . ,body)))

Böylece artık fonksiyonumuzu doğrudan

(defun-memo fn (x) ...)


olarak yazabiliriz. Emacs+SLIME ortamında dinamik makro açılımından faydalanarak .lisp dosyamızın içine

(defun-memo fib (n)
   (if (<= n 2) 1
      (+ (fib (- n 1)) (fib (- n 2)))))

yazalım ama derlemeksizin SLIME'ın makro açma özelliğinden (macro expand) faydalanmak için başına gidip C-c RET (yani önce Ctrl-C ardından da ENTER) basalım, SLIME bize ayrı bir ekranda aşağıdaki açılımı gösterecektir:

(MEMOIZE (DEFUN FIB (N) (IF (<= N 2) 1 (+ (FIB (- N 1)) (FIB (- N 2))))))


q tuşuna basıp geri dönebiliriz. Aynı bilgiyi edinmenin bir başka yolu ise doğrudan Common Lisp'in macroexpand-1'inden faydalanabiliriz:

CL-USER> (macroexpand-1 '(defun-memo  fib (n)
   (if (<= n 2) 1
      (+ (fib (- n 1)) (fib (- n 2))))))
(MEMOIZE (DEFUN FIB (N) (IF (<= N 1) 1 (+ (FIB (- N 1)) (FIB (- N 2))))))
T
CL-USER> 

Bütün bu makro muhabbetinin nelere kadir olduğunu görmek için Peter Seibel'in Practical Common Lisp kitabının Macros: Defining Your Own ve David B. Lamkins'in Successful Lisp kitabının Essential Macro Definition bölümlerine bakabilirsiniz.

"Memoization" tekniğini şimdi de hız açısından biraz inceleyelim. Bunun için önce fib fonksiyonunun özgün halini tekrar derleyelim, ardından da untrace ile izlemeyi kapatıp time ile analiz edelim:

CL-USER> (untrace fib)
WARNING: Function is not TRACEd: FIB
T

CL-USER> (time (fib 30))
Evaluation took:
  0.121 seconds of real time
  0.110983 seconds of user run time
  0.0 seconds of system run time
  0 page faults and
  0 bytes consed.
832040

CL-USER> (time (fib 35))
Evaluation took:
  1.321 seconds of real time
  1.236812 seconds of user run time
  0.002 seconds of system run time
  0 page faults and
  0 bytes consed.
9227465

CL-USER> (time (fib 36))
Evaluation took:
  2.237 seconds of real time
  1.962701 seconds of user run time
  9.99e-4 seconds of system run time
  0 page faults and
  0 bytes consed.
14930352

CL-USER> (time (fib 37))
Evaluation took:
  3.402 seconds of real time
  3.195515 seconds of user run time
  0.003 seconds of system run time
  0 page faults and
  0 bytes consed.
24157817

Şimdi bir "memoized" sürümü zaman açısından inceleyelim:

CL-USER> (memoize 'fib)
#<CLOSURE (LAMBDA (X)) {91F2545}>

CL-USER> (time (fib 34))
Evaluation took:
  0.0 seconds of real time
  0.0 seconds of user run time
  0.0 seconds of system run time
  0 page faults and
  8,096 bytes consed.
5702887

CL-USER> (time (fib 35))
Evaluation took:
  0.0 seconds of real time
  0.0 seconds of user run time
  0.0 seconds of system run time
  0 page faults and
  0 bytes consed.
9227465

CL-USER> (time (fib 36))
Evaluation took:
  0.0 seconds of real time
  0.0 seconds of user run time
  0.0 seconds of system run time
  0 page faults and
  0 bytes consed.
14930352

CL-USER> (time (fib 37))
Evaluation took:
  0.0 seconds of real time
  0.0 seconds of user run time
  0.0 seconds of system run time
  0 page faults and
  0 bytes consed.
24157817

CL-USER> (time (fib 400))
Evaluation took:
  0.0 seconds of real time
  0.0 seconds of user run time
  0.0 seconds of system run time
  0 page faults and
  0 bytes consed.
176023680645013966468226945392411250770384383304492191886725992896575345044216019675

Kendiniz de pratik olarak birkaç deneme yaparsanız özgün fib 50 gibi bir girdi için bile epey beklediğini, "memoized" fib'in ise 1000. Fibonacci sayısını dahi rahatlıkla kısa sürede hesaplayabildiğini (!) göreceksiniz. Burada detaylı bir algoritma karmaşıklık analizine girmiyoruz ancak meraklısı kaynakçada belirtilen PAIP kitabında bunları bulabilir.

Biraz Daha Gelişmiş Bir "Memoization"

Yukarıdaki memoize fonksiyonunun bazı eksiklikleri olduğunu fark etmiş olabilirsiniz, söz gelimi sadece tek parametreli fonksiyonlar için çalışıyor, "hash" tablosundan girdileri silmek için bir fonksiyon tanımlanmış durumda değil ve hash tablosunda değer ararken eşitlik kontrolü için sadece eql kullanıyor, oysa bazı durumlarda equal ya da eq kullanmak isteyebiliriz.

Aşağıda bu problemleri bertaraf eden memoize tanımlamalarını inceleyebilirsiniz:

(defun memo (fn name key test)
  "fn fonksiyonunun memo-fonksiyonunu döndür."
  (let ((table (make-hash-table :test test)))
    (setf (get name 'memo) table)
    #'(lambda (&rest args)
	(let ((k (funcall key args)))
	  (multiple-value-bind (val found-p)
	      (gethash k table)
	    (if found-p
		val
		(setf (gethash k table) (apply fn args))))))))

(defun memoize (fn-name &key (key #'first) (test #'eql))
  "fn-name'in global tanimini 'memoized' versiyonla degistir."
  (setf (symbol-function fn-name) 
	(memo (symbol-function fn-name) fn-name key test)))

(defun clear-memoize (fn-name)
 "Fonksiyonla iliskilendirilmis hash tablosunu temizle."
  (let ((table (get fn-name 'memo)))
    (when table (clrhash table))))


Sonuç

Bu yazıda Norvig'in meşhur PAIP kitabının 9. bölümünden yola çıkarak basit ama etkili bir optimizasyon yöntemi olan "memoization"ın Common Lisp ortamında nasıl uygulanabileceğini anlatmaya ve Common Lisp'in bazı özelliklerine dikkat çekmeye çalıştık.

"Memoization" genel bir teknik olup başka dillerde de uygulanabilmektedir. Söz gelimi buradaki örnekleri Java ile kıyaslamak isterseniz Tom White'ın Memoization in Java Using Dynamic Proxy Classes makalesine göz atabilirsiniz (özellikle Lisp lafını duyunca tüyleri diken diken olan Java programcılarına hitaben ;-). Yahut Mark Jason Dominus'un Memoize isimli Perl modülünü inceleyebilirsiniz.

Common Lisp'e yabancı olan ama öğrenmeyi düşünen programcılar Pascal Costanza'nın Çok Dik Başlı Lisp Rehberini okuduktan sonra Lisp ile TILSIMLI ve Renkli Programlama: Lisperatiyi okuyabilir ve Common Lisp Geliştirme Ortamı Kurulumu makalesine göz atabilirler.

Kaynakça




Emre "FZ" Sevinç
16 Eylül 2005, İstanbul
e-posta: emres at bilgi nokta edu nokta tr

Not: Yazının özgün adresi: http://ileriseviye.org/arasayfa.php?inode=memoize.html

Görüşler

0
tongucyumruk
Yanılıyorrsam düzeltin fakat yanlış anlamadıysam memoization işleminin sağlıklı çalışabilmesi için kullanılan fonksiyonların fonksiyonel programlama ilkelerine bağlı kalmaları şartı var. Örneğin bir fonksiyon global değişkenlerden faydalanıyorsa bu global değişkenin değerine bağlı olarak aynı parametrelerle çağrıldığında dahi farklı sonuçlar döndürecektir.

Bunun çözümü için belki global değişkenlerin de fonksiyonun parametreleri ile birlikte hash tablosuna kaydedilmesi düşünülebilir diye düşünüyorum.
0
FZ
Doğru anlamışsın. Zaten yazının sonunda MJD'nin bir Perl uygulamasına (Memoization modülü) link verdim, oranın "Caveats" kısmında ne tür fonksiyonların memolanmak için uygun olduğunu, hangilerinin uygun olmadığını detaylı anlatıyor. Ayrıca kaynakçada verilen CMU yapay zekâ kod deposunda da yine detaylı bir örnek mevcut. Öte yandan Common Lisp, fonksiyonel programlamayı dayatmamakla birlikte, Common Lisp programcıları o tarz programlamaya daha çok aşina oluyorlar, dolayısı ile yazıda bu çok vurgulanmıyor.

Global değişken durumlarının da "hash" tablosuna kaydedilmesi düşünülebilir belki ve hatta bu enteresan bir programlama problemi olabilir, belki defvar ve defparameter tarzında defmemo-var gibi bir şeyler tanımlanabilir fakat olası global değişken(ler) - fonksiyon kombinasyonlarının (bu sayı hızla artabilir) bir "hash" tablosunda tutulması ne kadar performanslı olacaktır bunu bir incelemek lazım.

Benim merak ettiğim şeylerden biri, Lisp kodlarını gördükten sonra o link verdiğim Java makalesindeki kodları gören insanların ne hissettiği.
0
yetgin
LISP çiler için üzüldüm :p
0
FZ
Valla benim de kusasım geldi :) Yani memoization işini yapan Common Lisp ve Java kodlarını kıyasladığımda. Amma uzun ve "verbose" olmuş, insanın kafası karışıyor o Java kodlarını görünce, anlamak kolay değil.
0
yetgin

Açıkçası LISP e çamur atmak için değil, tersini düşünen insanlar da olabileceğinin altını çizmek için yazdım o mesajı. Neden böyle olduğunu madde madde ıspatlamamı isteyen bir cevap vermediğiniz için de teşşekkür ederim, çünkü öznel bir şeyden bahsediyoruz. LISP kodları da benim kafamı karıştırıyor. Allak bullak oldum kodlara bakınca. Ama bunun neyle meşgulseniz ona (çok) daha aşina olmakla da ilgisi vardır herhalde.

Verbose olmanın kötü olması göreceli, öznel bir değerlendirme olsa gerek. Bir programlama dilinin önüne çıkarılan "ama çok verbose", "bak bu dille daha az kod yazıyorsun" tipi argümanlar bazılarımız için geçersizdir sanırım. Taki yazdığınız kodu kurgulamakla geçen zaman, yazmakla geçen zamandan daha kısalmaya başlayana kadar. Assembly de burada elimine oluyor herhalde. Kaldı ki modern programlama araçları, o fazladan (ama "bence" kodu okunaklı ve güzel kılan) kısımları sizin yazmanıza gerek bırakmıyor zaten.

Gerisi bana göre hikayedir, önemli olan ne ürettiğiniz. İster CL kullanın, ister SmallTalk, isterse COBOL.

0
FZ
Açıkçası LISP e çamur atmak için değil, tersini düşünen insanlar da olabileceğinin altını çizmek için yazdım o mesajı.

Tersini düşünen insanlar çoğunlukta zaten, buna aşinayız :) "İyi ama parantezler..." gibi boş argümanlarla günde en az iki kez muhatap olmazsam farklı bir ülkede yaşadığımı düşünüyorum (neyse ki uzun sürmüyor :)

Neden böyle olduğunu madde madde ıspatlamamı isteyen bir cevap vermediğiniz için de teşşekkür ederim, çünkü öznel bir şeyden bahsediyoruz. LISP kodları da benim kafamı karıştırıyor.

Her insan ayrı bir dünyadır, herkesin düşünme şekli farklıdır, birilerine aşikar gelen şeyi bir başkasına 3-4 saat anlatmak gerekebilir, bütün bunlar tamam. Bununla birlikte Lisp kodları benim kafamı karıştırıyor cümlesi bir adamın çıkıp yahu bu assembly program listesi ne kadar karışık demesinden daha anlamlı değil. Adama sorarlar: Afedersiniz ama temel assembly bilgisi edindiniz mi, birkaç hafta boyunca her gün birkaç saatinizi temel assembly bilgisi edinmeye ayırdınız mı? diye.

Kendi adıma konuşayım, belli bir seviyede Java biliyorum. Benzer dil ailesinden C ile bir süredir de C# ile de çalışmışlığım var. Yani o Java makalesinde ne yapıldığını anlamıyor değilim, "reflection" kavramı da yabancısı olduğum, ilk kez duyduğum bir kavram değil elbette, daha öncesinde kurcaladığım bir şey. Hal bu iken, bir Common Lisp uygulamasına bakıyorum, bir Java ile yapılmış uygulamaya, Lisp çok daha "doğal" görünüyor, "reflection" diye ayrıca bir şey söz konusu değil çünkü zaten Lisp öğrenirken, yüksek dereceden fonksiyonlar, meta programlama, vs. bunu dilin bir parçası olarak öğreniyorsunuz öyle ileri seviye, "advanced" falan filan şeklinde algılamıyorsunuz.

Verbose olmanın kötü olması göreceli, öznel bir değerlendirme olsa gerek.

Matematik haricinde her şey öznel olsa gerek.

Oradaki "verbose" lafım biraz da işin esprisi idi ama espride bir gerçeklik payı olduğunu da unutmayalım.

Bir programlama dilinin önüne çıkarılan "ama çok verbose", "bak bu dille daha az kod yazıyorsun" tipi argümanlar bazılarımız için geçersizdir sanırım. Taki yazdığınız kodu kurgulamakla geçen zaman, yazmakla geçen zamandan daha kısalmaya başlayana kadar. Assembly de burada elimine oluyor herhalde. Kaldı ki modern programlama araçları, o fazladan (ama "bence" kodu okunaklı ve güzel kılan) kısımları sizin yazmanıza gerek bırakmıyor zaten.

Javacıların klasik argümanlarından biri: Ben Eclipse kullanıyorum, ben Borland'ın filanca IDE'sini kullanıyorum, bak ne güzel "getter"ları, "setter"ları kendisi oturtuyor, vs. Kodun bir kısmının IDE tarafından üretilip dosyanın içine yazılması orada o kodun bulunduğu ve bakımının ("maintenance") yapılması gerektiği gerçeğini değiştirmiyor, bunu bir yere not edelim lütfen.

Bir başka nokta, tabii ki programla aracı önemlidir, elimizin altında Emacs + SLIME gibi bir ortam olmadan (ya da LispWorks ya da Allegro CL) Common Lisp geliştirmesi yapmaya kalkmak anlamsız bir hareket olur. Emacs + SLIME işleri, olması gerektiği gibi yani kolayca ve rahatça yapmamızı sağlar, gelişmiş debugging, profiling, tanımlar, çağıranlar, çağrılanlar, bağlam duyarlı (context sensitive) dokümantasyon arasında gidip gelmemizi sağlar. Bunlar iyi güzel şeyler ama dilin kendisinin getirdiği daha az şey yazarak daha çok etkiye yol açabilme, problemi daha kompakt şekilde ifade edebilme özelliği o programlama araçları ile, IDEleri ile alakalı değil ki. Bu bambaşka bir şey.

Gerisi bana göre hikayedir, önemli olan ne ürettiğiniz. İster CL kullanın, ister SmallTalk, isterse COBOL.

Bir başka sık karşılaştığımız argüman: Programlama dilini önemi yoktur. Yanlış. Programlama dili, nasıl düşündüğünüzü şekillendirir. Neden? Çünkü bir programlama dili, bir dil standardından, spesikasyonundan ibaret değildir. Söz gelimi PROLOG size bambaşka bir problem düşünme ve ifade etme yöntemi sunar. Common Lisp de öyle. Tabii ki önemli olan ortaya başarılı bir program koymaktır ama bu argüman, "o halde kullanılan araç önemli değildir" argümanına yol açmaz. Evet, yap da nasıl yaparsan yap ama bunu söyleyecek olan "müşteridir", son kullanıcıdır vs. Biz ise burada bilgisayarcılar arasında yazıştığımıza göre, bizim için işin "nasıl"ı önemlidir. Bu işi nasıl yapabiliriz, hangi araç bize ne tür avantaj sağlar? Bu dil, şu dile kıyasla nasıl bir ortam, avantaj, kültür, vs. sunar? Milyonlarda dolarlık reklam ittirmesi ile popüler hale gelmiş ve "endüstri standardı" (!) araçlar, diller, platformlar, vs. haricinde acaba adı sanı bizim çevremizde o kadar duyulmamış başka neler vardır, bunları duymak faydalı mıdır, o bilgilerden yola çıkıp acaba ufkumuzu genişletebilir miyiz gibi soruların gündemde olması normaldir.

Dilin insanın düşünce şeklini nasıl etkileyebileceğine dair güzel bir çeviri makale yayımlamıştık, orada Blub Paradoksu güzelce alınmış, tekrar tekrar okumakta ve düşünmekte fayda var:

Sıradışılıkla Kazanmak

Makalede, insanın hiç bilmediği bir şeyin farkına varmasının güçlüğü güzel örneklerle özetlenmiş.
0
myavuzselim
"Javacıların klasik argümanlarından biri: Ben Eclipse kullanıyorum, ben Borland'ın filanca IDE'sini kullanıyorum, bak ne güzel "getter"ları, "setter"ları kendisi oturtuyor, vs. Kodun bir kısmının IDE tarafından üretilip dosyanın içine yazılması orada o kodun bulunduğu ve bakımının ("maintenance") yapılması gerektiği gerçeğini değiştirmiyor, bunu bir yere not edelim lütfen."

Benim anlamadigim kodun "verbose" olmasinin kodun bakiminda nasil bir sorun teskil ettigi. Bana boyle bir kodun bakimi "sıkıstırılmıs" bir kodun bakimindan daha kolay olurmus gibi geliyor.
Lisp'in bazi avantajlari var, evet. Ben de bu yuzden lisp ile ilgilenmek isterim. Ama bence "verbose" olmamasi lispin (onemli) bir avantaji degil.
0
FZ
"Verbose"dan ne anladığımıza dikkat etmek lazım. Söz gelimi Common Lisp'teki değişken ve fonksiyon isimleri pek kısa değildir aralarına tire konularak uzun uzun yazılmış olduklarını görürsünüz (evet, burada Lispçiler, diğerleri gibi Emac+SLIME, ya da LispWorks, ya da Allegro ya da Symbolics Lisp Machine'in kod tamamlama gücüne haklı olarak güvenmektedirler). Bu açık açık yazma hali kısaltmalarla boğuşmaktan kurtarır insanları. Bu bakımdan Lisp'e "verbose" denilebilir, netekim bir Perlci bunu rahatlıkla söyleyebilir mesela. Öte yandan bir çözümü ifade edişinizdeki sadelik, kompaktlık da bir kriter olabilir, dil, bu bakımdan "verbose" olmayabilir, soyutlamaları kullanarak pek çok şeyi az şeyle ifade etmenize izin verebilir (bkz. PROLOG, Reg Ex, vs.). Yani biraz da hangi açıdan baktığımıza bağlı.

Benim kast ettiğim sözcüksel, harfsel (lexical?) "sıkıştırma", "verbose" olma olmama hali değildi tahmin edersiniz ki.

Öte yandan, kod miktarınız büyüdükçe bunu ister siz yazmış olun, ister kullandığınız araç dosyanın içine boca etmiş olsun dikkat etmeniz gereken şey sayısı da artacaktır. Karmaşıklık artacaktır. Zaten bu yüzden Java ya da C# ortamında araca ürettirilmiş koda müdahale edilmemesi, aracın girdi kabul ettiği şeye müdahale edilip tekrar kodun otomatik ürettirilmesi tavsiye edilir, gayet haklı olarak (getter, setter örneği bu bağlamda çok iyi örnek olmayabilir onu söylememin sebebini yukarıda belirtmiştim).

Eğer Lisple ilgilenmek istiyorsanız, FM'de pek çok makale bulabilirsiniz, yavaş yavaş kıpırdanmalar başlıyor, çalışma grupları kuruluyor, vs. Common Lisp'in avantajlarını yüzeysel bir bakışla değil bir Lisp geliştirme platformunda çalışmaya başlayıp sorunlarınızı çözdükçe, sorularınıza cevap aldıkça fark etmeye başlarsınız. Ama cicili bicili milyon dolarlık tanıtım ve reklam kampanyaları, Microsoft, Sun, IBM, vs. desteği ile pek karşılaşmayacaksınız. Çok hit alan O'Reilly, vs. gibi popüler sitelerde karşınıza Lisp ne güzel bir dildir diye 1 sf.lık makaleler çıkmayacak, çok popüler isimlerin Lisp'ten bahsettiğini duymayacaksınız. (Gülmeyin insanlar etkileniyor bunlardan). Yine de ilgilenmeye devam ederseniz, o zaman herhalde biraz eğlenceli vakit geçirebilecek ve bazı durumlarda epey şaşıracaksınız ;-) (bkz. comp.lang.lisp'te gezinen acemi çaylakların, a-aaa, vay canına, aa, bu kadarla mevzu halloluyor mu? nidaları).
0
darkhunter
A extension library that adds memoization support to CMU-CL


http://packages.debian.org/unstable/libs/cl-memoization

0
FZ
cl-memoization'a dikkat çektiğin için çok teşekkürler. CMU-CL demiş ama acaba diğer Lisp derleyicileriyle de uyumlu mudur (mesela ben SBCL kullanıyorum), eğer değilse uyumlu hale getirmek güzel bir katkı olabilir.
0
anonim
CPU cycle sayısını dusurmek, yapılacak islemi onceden bir kere yapıp cok kez kullanma amaclı teknikler bruteforce sifre-kırma saldırılarında kullanılmaktadır.

Zaman-bellek degisimi, 1980lerde Martin Hellman tarafından ortaya atılmıs, Rivest tarafından gelistirilmis en son olarak, Philippe Oechslin tarafından optimize edilmis, bir teknik olup sozkonusu butun sifre olasılıkları onceden hesaplanıp, bellek(sabitdisk) kaydedilip son olarak da indexlenip kullanmaktadır.

Sifre olasıklarında kullanılacak degisik karakter sayısı ve sifre uzunlugu hesaplanacak degerlerin ne kadar bellek kullanacagını belirler. Ornegin LM hashing hesaplaması icin

[ABCDEFGHIJKLMNOPQRSTUVWXYZ] karakter seti icin gereken bellek 610mb

[ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789] karakter seti icin gereken bellek 3 GB

[ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_+= ] karakter seti icin gereken bellek 64 GB

Sozkonusu degerler bir kez hesaplanabilip, cok kez kullanılabilir. Onceden hesaplamak ve indexlemek icin harcanan cpu zamanının dısında, HDD de hash degerinin karsılastırılması icin harcanan zaman sozkonusudur. Bu da bruteforce saldırıları icin harcanan zamana gore cok daha azdır.
0
FZ
Bakalım yazmış ve yazması beklenen insanlar haricinde Common Lisp lafı eden birileri çıkacak mı, yazıyı yazma sebeplerimden biri de somut ve ne çok basit ne çok karmaşık olan bir konu üzerinden Lisp'in (Common Lisp'in) kullanımına dair örnekler aktarmak idi.
0
bm
Ya sen boyle seyler yazmaya basladigina gore, beni 'yazmasi beklenen' insanlar listesinden cikartabilirsin herhalde. Yazmama bir ihtiyac kalmamis gibi gorunuyor cunku. Eline saglik.
0
FZ
Hani bazen tartışmalar alevleniyor ya, yok efendim insanlar şuna alışamaz, yok filanca programlama diline adapte olmak çok zor, yok filanca arayüz en iyisi, sen milyon dolarlık şirketten iyi mi bileceksin filan...

Bugün gördüğüm iki alıntı çok hoşuma gitti:

"People are smarter than appliances. They can learn. People like learning. People can learn to work with tools. Computers are tools. People like to learn how to use things that work."

Ve bir başka alıntı:

"Contact with the programming written under alien conventions may help. Visiting MIT on sabbatical this year, I have seen numerous examples of the programming power which Lisp programmers obtain from having a single data structure, which is also used as a uniform syntactic structure for all the functions and operations which appear in programs, with the capability to manipulate programs as data. Although my own previous enthusiasm has been for syntactically rich languages like the Algol family, I see now clearly and concretely the force of Minsky's 1970 Turing Lecture, in which he argued that Lisp's uniformity of structure and power of self-reference gave the programmer capabilities whose content was well worth the sacrifice of visual form."

Meraklısı belki düşünür, araştırır ve bulur yukarıdaki sözleri kimlerin sarf ettiğini. (Çevirmeye korktum şimdi, benden önce davranan biri olmazsa belki birkaç gün içinde çeviririm).
0
FZ
Not: Gecenin iki buçuğunda üşenmeyip yazıyı gözden geçiren ve bazı hatalara dikkat çeken Lisp programcısı dostum Haldun Bayhantopçu'ya da buradan teşekkürler. Benim yazıyı eleştirdikten sonra da Overloading functions in Common Lisp başlığı altında comp.lang.lisp'i birbirine katmaya gitti :) Bu arada Lisp: 4th Most Frequently Used Language in Debian GNU/Linux tartışması ise genellikle comp.lang.lisp'te olduğu gibi aldı başını gitti, son baktığımda GNU Emacs'ın Scheme tabanlı olması, CL'deki "keyword" mevzusunun aslında ne kadar güzel olduğu (evet, bence de gayet güzel ve avantajlı), Richard Stallman'ın sırf kendisi tasarlamadığı için Common Lisp'e gıcık olduğu gibi konular ele alınıyordu :)

Bu arada tabii yine Emacs, Lisp machines, UNIX mevzuları geçiyor ortamda, görülen o ki "UNIX (GNU/Linux), Emacs için bir önyükleyicidir." (UNIX is just the Emacs boot-loader.) Bkz. Emacs standing alone on a Linux Kernel.
0
yetgin
Evet RMS Java yıda sırf kendisi tasarlamadığı için gıcık oluyormuş. Öyle diyorlar.
0
conan
Lisp lisp lisp yeter be, basimiza tas yagacak! :) Biraz da baska seyler yazin. hehe ;) Mesela AMAN TANRIM IPOD NANO SUPER filan gibi...
0
FZ
:) Valla portatif MP3 çalar fetişizmi, Apple fetişizmi, vs. yeterince var etrafta. Benim pek o taraklarda bezim yok, müzikle çok ilgili bir adam olmakla birlikte, bırak öyle portatif MP3 çalar, normal walkman'e adapte olmuş bir adam değilim.

Joel Spolsky mi neydi, yine iPod geyiği yapmış, yaa ne güzel tasarıım yaa, bakın böyle klik! klik! yapıyor, insana bir şeyleri kontrol ettiği hisini veriyor filan diye yazmıştı, manyak mıdır nedir demiştim. Tamam olabilir, etkilenmiş olabilirsin filan da, abartmayalım yani. (Abartmam, abartana da karışmam).
0
tongucyumruk
"iPod isteme benden, buz gibi soğurum senden" diye buyurmuş atalarımız... Gerçi konuyla alakasız olacak ama şu iPod denen şeyin diğer Mp3 çalarlara olan üstünlüğünü açıklayabilecek bir insan evladı varmı acaba? Yahu alet USB Mass storage olarak bile çalışmıyor, şarkı yüklemek için ekstra program gerektiriyor.

Ben her şehre indiğinde yaklaşık 1 saat yol giden bir insan olarak, her ne kadar müzikle dinlemekten öte bir ilgim olmasa da, mp3 çaları olsun, walkman'i olsun hepsiyle uğraşan teknoloji düşkünü bir tüketim toplumu bireyi olarak iPod yerine şu güzelle ilgilenmeyi tercih ediyorum... Ah bir de Ogg/Vorbis çalsa bir dakika daha beklemeyeceğim ama...
0
darkhunter
Sizin "şu güzel"in LCD ekranının işlevini pek anlayamadım. Bu aletle haşır neşir oldunuz anladığım kadarıyla, siz anladıysanız bana bir anlatıverin lütfen... Bu ekrana kim bakıyor? Karşıdan gelen vatandaş mı?
0
tongucyumruk
Öngörüldüğü şekilde kullanıldığı sürece o LCD ekran gerçekten anlamsızlıkta uç noktalardan birini oluşturuyor. Ancak arkadaşın kendi kulaklığının devre dışı brakılıp dışarıdan ekstra kulaklık bağlanması mümkün. Belki o şekilde kullananlar varsa ekran onların işine yarıyordur.
0
conan
Tonguc'cum. iPod'u anlamak icin vahsi pazarlama stratejilerine yatkin bir beynin olmasi lazim, renkli arkaplanlarin onunde sicrayan New York City genclik siluetlerini, renkli dugmeleri, binbir arka urunu almaya hazir bir cuzdanin onemini, ayni isi yapan 12bin3yuzelli2 tane daha urununun oldugunu bilmene ya da bilmemene ragmen bu urunu istemeye hazir ve nazir, bunun icin kuyruklarda beklemeye ustune para vermeye niyetli olman lazim. Anlayamiyorsun, cunku beynin bunlari reddediyor.

iPod'suz zavalli azinliga katil sen de lutfen, gel yanima otur. ;) Bak ben podcasting yapan station'dan iTunes'uyla catir catir muzik dinleyen super netjunky arkadasima gipta ile bakiyorum burda, sen de bak.

Ben iPod yerine nokia 6320 ve de 1 GBlik mmc card kullaniyorum. Zaten 1 GB'dan daha fazla muzigi benim beynim almiyor. Yani yanimda hangi sarki tasidigimi bile bilmeyecek hale geliyorum. Telefon disari da ses veriyo, aksam icerken filan fasil bile yapabiliyoruz nokia'yla :P Eminim bunlari iPod'la da yapiosundur. Ama olsun :)
0
sametc
Tonguc'cum. iPod'u anlamak icin vahsi pazarlama stratejilerine yatkin bir beynin olmasi lazim, renkli arkaplanlarin onunde sicrayan New York City genclik siluetlerini, renkli dugmeleri, binbir arka urunu almaya hazir bir cuzdanin onemini, ayni isi yapan 12bin3yuzelli2 tane daha urununun oldugunu bilmene ya da bilmemene ragmen bu urunu istemeye hazir ve nazir,

çok doğru katılıyorum... imzamı atıyorum : sametc....... :P
0
Geryon
Sanırım ben anlamadım :(
bu bana look up table gibi gözüktü ???
0
FZ
Anlamadığınız bir şey varsa, buyrun biraz daha detaylı sorun, birlikte anlamaya çalışalım. Look up table mıdır, nedir, vs. Yalnız önce yazıyı bir kez daha baştan sona okumanızı hatta bununla yetinmeyip yazının sorunda verilen linklere de bir göz atmanızı tavsiye edeceğim (misal, MJD neden Memoize.pm demiş de DarnSameOldEasyLookupTable.pm dememiş filan).
0
FZ
İkinci bir cevap vereyim, çok kısa bir özet geçerek:

- Memoization yeni bir şey değildir, evet. (1968 yılında ortaya atıldığını belirttim yazının başında).

- Başka dillerde de yapmak mümkündür, evet, örneklerine bizzat link verdim zaten.

- Memoization, bir "hash" tablosu ya da benzeri bir veri yapısı vasıtası ile hesap yapmak yerine doğrudan hafızadan veriyi çağırmakla ilgilidir, evet. "Hash" tablosuna, "lookup tablosu" da denebilir mi, evet denebilir. Bu, memoization yönteminde kullanılan bir veriyapısıdır, yöntemin kendisinin ismi değildir.

- Bu yazımızda, herhangi bir fonksiyonun, yüksek dereceden (higher order) fonksiyonlar vasıtası ile nasıl elle kendisine müdahalede bulunmadan "memoized" yani "memo"lu hale getirileceği ve eldeki araçları yani güçlü Common Lisp makrolarını kullanarak doğrudan "memoized" halde nasıl tanımlanabileceği gösterilmiştir. Amaç, basit bir optimizasyon yönteminin olabildiğince genel halini vermek, buna dikkat çekmek ve bu bağlamda Common Lisp'in bazı noktalardaki gücüne dikkat çekmektir.

- "Ben 80'li yılların başında assembly ile (ya da C, ya da Forth, ya da her ne ise) zaten sin(x) için cos(x) için süper lookup tablosu yapıp acayip 3D demo yapıyordum Commodore ile ne ki bu memoization, peh!" demeyi akıllarından geçiren değerli FM üyelerine ekstradan bir açıklama yapılmayacak, sükunet korunacaktır.
0
yetgin

Yazar aşağıdaki linkte memoization tekniğini Javascripte uyguluyor. Pek iyi JS bilmediği, bir iki noktanın daha da düzeltile(bile)ceğini öne sürüyor. Kendisi bir open source proje için yaklaşık 4-5 gün Javascript kurcalayarak bu kodu yazacak hale gelmiş! Demekki sadece yetenekli değil ayrıca da basit bir dil.

www.usturlap.com

Ben de hepinizi Javascript kullanmaya davet ediyorum. Java, C, Smalltalk geçin bunları; arrayleri anladınız mı olay bitmiştir. Javascript de malum dil gibi arraylerden ibaret dir. Ustelik daha basittir.

Midir?!
0
FZ
Biraz uykusuz bırakacak kadar sizi motive edebildiysek ne mutlu bize :)

Makalenizi Türkçe yazsaydınız anlamak daha kolay olacaktı, bazı yerlerdeki İngilizceyi anlamakta çok güçlük çektim (mutlaka İngilizce yazmış olmanızın mantıklı bir açıklaması vardır ama böyle bir şey yapacaksanız işleri zorlaştırmamanız ve imalarda bulunmak yerine aklınızdan geçeni açık olarak yazmanız okurlar açısından daha iyi olur, özellikle de Türkçe bir makeye referans veriyorsanız).

Verdiğiniz örneğe gelince, fena bir örnek değil, birtakım başka kavramlardan haberdar olan ve JScript ile ilgilenen bir programcının JScript ile memoization'ı nasıl yapabileceğini gösteren bir örnek.

Dikkatimi çeken noktaları sayayım:

16 satır Common Lisp kodu, 28 satır JavaScript kodu var.

28 satırlık JavaScript kodunda olmayıp da 16 satırlık Common Lisp kodunda olanlar:

- Bir derleyici ile etkileşimli olarak çalışma imkanı.

- Fonksiyon tanımı değiştiğinde tek harekette bunun memolu hale gelmesini sağlayan makro (yani önce fonksiyonu değiştir, sonra derle, sonra memo yap değil, fonksiyonu değiştir, derlediğin andan itibaren zaten memo özelliğine sahip).

- n elemanlı fonksiyonlara doğrudan destek (kodda düzenleme yapmayı gerektirmeden).

- Kullanılan hash tablosunu temizleyebilme.

Yukarıdaki özellikleri ilgili Jscript koduna eklemek zor mu, değil elbette, bir miktar daha uzun hale gelir hepsi bu, atla deve değil elbette. Bir derleyici ile etkileşimli çalışma, Emacs+SLIME ortamı vs. alakasız gibi görünebilir, bu yüzden onu en başa yazdım biraz vurgulamak için, dilin özelliği olmamakla birlikte geliştirme ortamının özelliği (Java'cıların Eclipse, vs. argümanlarına ithafen).

Beni JScript'e davet etmenize sevindim ancak buna gerek yok, zaten yıllardır kullanıyoruz muhtelif işler için ve birtakım güçlü özelliklerini Lisp'ten aldığını görüp seviniyoruz.

(Bu arada şimdi fark ettim, sanırım programı 1-2 satır kısaltabilirsiniz çünkü memoizedFunctsArr dizisini tanımlamış ve burada bilgi depolamışsınız ama bu bilgiye başka hiçbir yerde referansta bulunmamışsınız).

Kaçıranlar için bir daha belirteyim, yazdığım makalede memoization'ın dilden bağımsız bir optimizasyon tekniği olduğunu belirttim. Ardından Common Lisp'in bazı güçlü özellikleri kullanılarak bunun nasıl gerçekleştirilebileceğine dair birkaç örnek verdim, hem memoization'ı hem de arada Lisp'in bazı özelliklerini açıklamaya çalıştım. Makalenin sonunda da başka dillerdeki mevcudiyetine dair (Java ve Perl) bazı örneklere link verdim ki insanlar kıyaslayabilsin anlatılan bir örnek üzerinden dilleri diye. Daha sonra, karşılıklı tartışma esnasında, Java'da yapılmış hali ile ilgili espri ile karışık bir iki eleştirim oldu (normalde Java aklımda değil de, nedense Common Lisp'ten bahsettiğimizde %99 Javacılar gelip, ya ama siz de hep Lisp'ten bahsediyorsunuz, olmaz ki canım gibi argümanlarla karşımıza çıkıyorlar, ister istemez bende çağrışım yaratıyor :).

Hal bu iken

Ben de hepinizi Javascript kullanmaya davet ediyorum. Java, C, Smalltalk geçin bunları; arrayleri anladınız mı olay bitmiştir. Javascript de malum dil gibi arraylerden ibaret dir. Ustelik daha basittir.

gibi bir yorum ile karşılaşınca açıkçası şaşırıyorum ve tam olarak ne diyeceğimi kestiremiyorum. (Tam olarak ne denmek istendiğini anlasam cevap vereceğim ama Türkçe cümlelerden, İngilizce yazılardan da çok şey anlayamadığım için tam bir bir cevap veremiyorum).

Not: Uykusuz kalmaktan bahsedilmiş, buna ne kadar gerek vardı bilmiyorum, mevcut bazı örnekleri incelemek daha verimli olabilirdi gibi geldi şimdi bana:

http://interglacial.com/hoj/

http://www.bigbold.com/snippets/tag/recursive

http://dren.ch/20050715.html

Yüksek Dereceden Fonksiyonları Keşfetmiş ve Bunlarla Oynayıp Bunları Sevmiş JScript Programcılarına Not: Common Lisp'e göz atmanızda fayda var, 4-5 günden daha çok vaktinizi alacaktır ve bazı bakımlardan "basit" bir dil değildir ama sizi 4-5 günden daha uzunca bir süre eğlendireceği ve eğiteceği kesindir. (SmallTalk programcılarına özel indirim var, ne de olsa Alan Kay, Lisp'in gücünü (SmallTalk örnekleri vermeye kalkışmadan) pek çok kez ifade etmiş saygı duyduğumuz bir üstadımızdır. :))
0
bm
O listeye bir de bignum destegi eklenebilir konu fibonacci filan gibi fonksyonlarsa. Hiz olculdugunu gormedim o yazida, dili uygulama kaliesi bakimindan fikir verebilir bir bakmak.

Genelde makalede CL ile gosterilen teknik 'late binding' yapabilen ve 'lexical closure' kullanmayi kolay hale getiren her dile o kolaylikla uygulanabilir. Nesneler de bir cins closure tabii, ama Javascript dogrudan lexical closure da yaratabiliyor olmali, bilmiyorum ama oyleyse o nesneyi kullanmaya gerek yok.

Buradaki CL tanitim cabasinin arkasinda 'herkes bunu kullansin'dan ziyade 'buna bakmak ve ogrenmek size faydali olabilir' fikri var. Bu arada aldigimiz tepkiler kimin kac milyon satir kod yazdigindan, kimin kavramlari ne kadar hizli kapip ne kadar kisa zamanda ve uyku handikapina ragmen uygulayabildigine kadar FMciler hakkinda iyi birseylerin aciga cikmasina de vesile oluyor. Biz o tarafini dusunmemistik pek, ama o da zararli degil tabii. Memlekette CL'e burun kiviracak kadar bilgisayar bilimine hakim insanlarin FM gibi yerlerde digerlerine bilgi verdiklerini gormek de benim hosuma gidiyor.
0
FZ
bignum ve hız mevzuları aklıma geldi benim de ama en nihayetinde muhatap olduğum şey JavaScript olduğu için pek üzerinde durmadım, yoksa mesela memolu olmayan halinde fib(32) yaklaşık 15 sn. bekliyor, memolu fib(400) ise beklendiği şekilde yığıt taşması hatası döndürüyor. Bunlar IE 6.0'da olanlar, Firefox'ta ise fib(32) (memosuz) yaklaşık 5 sn. sürerken, memolu fib(400) ise 1.760238064501e83 değerini döndürüyor (bir kez daha Mozilla ekibine buradan teşekkürlerimizi iletiyoruz). Bu denemeleri Intel Pentium IV, 2.80 Ghz bir makinada yaptım (MS Windows), özgün makaledeki denemeler ise (CL ile olanlar) Intel Celeron 1 Ghzlik bir makinada gerçekleştirilmişti (Debian GNU/Linux çalıştırırken).

0
yetgin
Bir sey demenize gerek yok, oturup aynı işi Javascript te yapmak olsa olsa, mizahi bir bakıs acısı olarak algılanmalı. Belki mesajım cok ciddi duruyor. Dedigim gibi, uykusuzdum ondandır. Ha uykusuzlugumun sebebi o Javascript degil, oradan bindirme yapmanıza gerek yok. Yorgun oldugum halde uyuyamayıp bilgisayarın basına oturdum geceyarısı.

Linkler için tesekkür ederim. memoize metodunu objenin prototipine ekleyerek bütün fonksyonları memoizable yapmak daha guzel bir yaklasım.

fibonachi.memoize() diyerek yani.

Satır sayısına lutfen girmeyelim. Tamamı 2 satır olarak yazılabilir çünkü. Yada örneğin memoize metoduna geçilen argümanın fonksiyon olup olmadığı kontrolu, okuma kolaylıgı olsun diye. Ayrıca tek parantez olan satırları da sayıyorsanız; onları komutların sonuna koyarız olur biter ;) Zaten yazıdaki koduda biraz daha toparladım Yine de Lisp le Javascript karsılastıracak kadar dingil deilim.

Yazıda da dediğim gibi, emeğinize saygı duyuyorum ve ekliyorum. Devamını bekliyorum. Benim bastan beri amacım, burada Java misyonerliği yapmak değil. O işler 7 yıl falan önceydi. Ayrıca mizah da olsa, flame de olsa konuya da katkım olduğunu düşünüyorum. (Hemen kendime pay cikarayim :p )



0
FZ
Gecenin bir körü bir FM üyesi böyle eğlenceli bir konuda yazar da ben cevap vermez miyim :) (Gerçi ben sabah 7 sularında cevap vermiştim ama ben de hiç uyumamıştım, benzer ruh halini kabul edebilirsiniz yani ;-)

JScript'in bazı güçlü özelliklerini vurgulamış olmamız da bence fena olmadı her ne kadar temelde Common Lisp'ten bahsetmeye çalışıyor olsak da. (Bkz. böyle "flame"e can kurban).

Satır sayısına girelim, "idiomatic" Lisp kodu idi gördüğünüz ve nasıl derler, "best practices" mantalitesine uygun, okunaklı yazılmıştı. Dolayısı ile JScript kodunu dip dibe ekleyebileceğinizi iddia etmeniz haksızlık olur çünkü okunabilirlik ve düzgün stilden taviz vermek gibi bir niyetimizin olduğunu sanmıyorum.

Ben de muhabbete katkınızın olduğunu düşünüyorum, dediğim gibi bu şekilde bir motivasyon yaratabiliyorsak ne güzel. Benim burada gördüğüm şu, sanırım biraz daha farklı bir Lisp örneği vermek gerekecek ki ilk aklıma gelen Practical Common Lisp'in ilk esaslı bölümü, hani şu SQL benzeri bir dilin birkaç satırda geliştirildiği bölüm. Gerçi kitap açık ama tabii kaç kişi gidip bakıyor bilmiyorum, o bölümden "esinlenerek" o SQL dili geliştirme örneğini vermek doğru olur mu bilmiyorum, belki biraz kısaltarak ve biraz modifiye ederek ve de kitaba link vererek anlatmak güzel olabilir, hem kitaba olumlu katkıda bulunmak hem de İngilizce okumaya üşenenler için bir şeyleri göstermek hem de Lisp'in gücüne dair yine sağlam bir örnek vermek için.
0
bm
Ben kullanmadim ama hos gozukuyor:

http://lxr.mozilla.org/mozilla/source/js2/semantics/

Görüş belirtmek için giriş yapın...

İlgili Yazılar

Land Of Lisp Çıktı

okanakyuz

İleri seviye sitesindeki lisperati (Tılsımlı Programlama) (http://ileriseviye.org/Makale/lisperati-tr/) metninin orjinalinin yazarı Conrad Barski en sonunda bir lisp kitabı çıkarttı. Kitap Lisp diline bir türlü alışamayan meraklılar ile yeni başlayan kullanıcılara hitap ediyor. Ayrıca lisp dilini komik hikayeler ve karikatürler ile anlatmakta. http://landoflisp.com/ sitesinden kitabın 8nci bölümünü okumak da mümkün.

Video: Second Episode - 20 dakika ve 100 satırda Reddit

FZ

Video çılgınlığı devam ediyor. Bu gidişle HOW-TO belgelerinin yerini HOW-TO videoları mı alacak? İnsanlar "öğret bana usta, adım adım göster" yaklaşımını daha mı çok seviyorlar? Daha önce duyurduğumuz videoyu yapan Sven Van Caekenberghe'nin Episode 2: (Re)writing Reddit in Lisp is 20 minutes and 100 lines videosu taze taze, sıcak sıcak kamuya sunuldu.

Lisp'i Anlamak

anonim

Fazlamesai'deki Lisp hayranları bunu nasıl atladı bilmiyorum ama digg.com'da rastladığım, biz ölümlülerin kullandığı sıradan programlama dilleriyle uğraşanların da anlayacağı bir dille yazılmış The Nature of Lisp başlıklı bu yazı, Lisp hakkında şimdiye kadar okuduklarımın toplamından daha fazla şeyi anlamamı sağladı.

Kent Pitman Lisp ve ötesi ile ilgili soruları yanıtladı - Bölüm 2

FZ

Kent Pitman, 2001 yılının sonuna doğru Slashdot camiasının Lisp/Scheme, standartlar, yazılım geliştirme ve diğer konulardaki sorularını cevapladı, meraklarını giderdi. Bir hayli detaylı olan bu soru cevap seansı uzunluğundan ötürü iki bölümde yayınlandı. İkinci ve son bölümü, Bilkent Üniversitesi, Bilgisayar Müh. bölümü öğrencisi Hayrettin Gürkök'ün çevirisi ile karşınızda... (1. bölüm burada, 2. bölümün ilk kopyası ise ileriseviye.org adresinde)

Barack Obama'yı Semantik Web Üzerinden Lisp ile Sorgulamak

FZ

Öyle bir veri tabanı düşünün ki şu sorunuza doğru cevaplar veriyor: "Barack Obama nerede doğmuştu? (Nerede dünyaya gelmişti diye de yazabilirsiniz) Doğduğu yere 15 km uzaklıktaki şehirler ve kasabalar hangileri idi? 2000 yılında bu yerleşim yerlerindeki ortalama fakirlik seviyesi ne idi?"

Bunu tek bir ilişkisel veri tabanı ile kolayca yapabilir misiniz? Yahut daha doğru soru: Neden tek bir veri tabanı olsun ve bu neden ilişkisel olsun? Buyrun semantik web ve RDF kullanın. Nasıl mı?