Diyelim Ki Elimizde Nesneye Yönelimli Bir Dil Yok - Alice Nesneler Diyarında

0
FZ
Elinizdeki programlama dilinde nesneye yönelimli (OO - Object Oriented) programlama imkanı olmasa idi ne yapardınız? İki seçenekten biri gelirdi aklınıza herhalde:
  1. OO desteği veren bir dil kullanmaya başlamak.
  2. Elinizdeki dile OO desteği katmak için uğraşmak.
Bu kısa yazıda Peter Norvig'in PAIP (Paradigms of Artificial Intelligence Programming Case Studies in Common Lisp) kitabının 13. bölümündeki birkaç kısa örnekten yola çıkarak "eğer Common Lisp dilinde CLOS (Common Lisp Object System) gibi bir şey olmasaydı bunu nasıl gerçekleştirebilirdik?" sorusunun cevabının ilk bölümüne göz atacağız.

Nesnemiz Kalmadı Onun Yerine "Closure" Versek?

Ne demiştik? Elimizde sınıf, nesne, metod, vs. mekanizmasının olmadığını var sayacaktık ama en nihayetinde elimizde Common Lisp varsa, o zaman fonksiyon var demektir, lambda var demektir. Halbuki biz istiyoruz ki mesela "hesap" gibi bir nesnemiz olsun, bu hesabın bir ad özelliği olsun, sonra mesela bakiye ayarlayan, para çekip para yatırmamızı sağlayan bazı metodları olsun. Bir nevi OO programlama olsun, hayat daha güzel olsun...

O halde şimdi sadece defun, lambda, vb. Lisp yapılarını kullanarak bir fonksiyon yazalım, öyle bir fonksiyon olsun ki ismi yeni-hesap olsun, "ad" isimli bir parametre alsın, bir de eğer verirsek aldığı ama vermezsek birtakım varsayılan değerler atadığı "bakiye" ve "faiz-oranı" gibi iki parametre daha olsun. Ve bu fonksiyon bize aslında basit bir değer yerine bir fonksiyon döndürsün, öyle bir fonksiyon döndürsün ki bu döndürdüğü şey de aldığı "message" isimli parametrenin içeriğine bakıp iş güç yapan bir fonksiyon olsun. Yeterince kafa karıştırıcı oldu mu? İşte bu kafa karışıklığını gidermek için doğal dil yerine Common Lisp kullanıyoruz ve şunu yazıyoruz:

(defun yeni-hesap (ad &optional (bakiye 0.00) (faiz-orani .06))
  "Belli mesajlara tepki veren yeni bir hesap yaratalim"
  #'(lambda (mesaj)
      (case mesaj
        (cek #'(lambda (miktar)
                      (if (<= miktar bakiye)
                          (decf bakiye miktar)
                          'yetersiz-bakiye)))
        (yatir  #'(lambda (miktar) (incf bakiye miktar)))
        (bakiye #'(lambda () bakiye))
        (ad     #'(lambda () ad))
        (faiz #'(lambda ()
                      (incf bakiye
                            (* faiz-orani bakiye)))))))

Pekiyi güzel ama yukarıdaki fonksiyonu çalıştırırsak ne döndürecek? Süper etkileşimli REPL (Read Eval Print Loop) ortamına geçelim ve deneyelim:

CL-USER> (yeni-hesap "fz'nin banka hesabi")
#

Çok anlaşılır görünmüyor. Acaba bu döndürdüğü şeyi bir değişkene atasak?

CL-USER> (defvar *hesabim* (yeni-hesap "fz'nin banka hesabi" 100 0.09))
*HESABIM*
CL-USER> *hesabim*
#


Hala çok anlaşılır gibi değil. Bir "closure" yarattığımızı ve bunu *hesabim* isimli bir değişkene yerleştirdiğimizi belirtiyor ama acaba gerçekten nesne benzeri bir şey yarattık mı? (Bu arada eğer başarılı olduysak havadan 100 YTL sahibi olacağım, üstelik %9 faiz oranı ile, o halde devam etmeye ve denemeye değer! ;-)

Şimdi madem fonksiyon döndüren fonksiyon gibi bir şey yazdığımızı söylemiştik o halde, *hesabim* gerçekten de böyle garip bir varlık mı bir kontrol edelim:

CL-USER> (funcall *hesabim* 'ad)
# (funcall *hesabim* 'bakiye)
#
CL-USER> (funcall *hesabim* 'yatir)
#


*hesabım* isimli "closure"a "madem ki sen closure türünden bir şeysin, fonksiyon döndüren bir şeysin ve öyle bir fonksiyon ki bir parametre bekliyorsun o halde seni funcall ile çağırayım ve beklediğin parametreyi vereyim" dedik ve yukarıdaki birkaç sonucu elde ettik. Bize yine "closure" döndürdü, yani çağrılmayı bekleyen fonksiyonlar. O halde zincirdeki son halkayı tamamlayalım:

Yukarıdaki ilk satıda dikkat ederseniz *hesabım*'a 'ad parametresi geçildiğinde bize onunla ilgili bir "closure" yani çağrılmayı bekleyen bir fonksiyon döndürüyor, pekiyi bu dönen fonksiyon parametre olarak ne bekliyor? Hiçbir şey. Yani NIL. O halde:

CL-USER> (apply (funcall *hesabim* 'ad) nil)
"fz'nin banka hesabi"

Şimdi durum biraz berraklaşmaya başladı gibi değil mi? Ama hala çok ilkel durumdayız. İşleri kolaylaştıracak birkaç fonksiyon tanımlasak, hani şu alışık olduğumuz OO tarzı var ya, bir nesneye bir mesaj (Java'cılar, C#'çılar bunu metod diye okuyabilir) geçiyoruz, o mesaja da bazı parametreler veriyoruz ve sonuç elde ediyoruz filan yani şöyle bir yapımız olsa:

send nesne mesaj p1 p2 p4 ... pN

bir nevi

nesne.metod(p1, p2, ..., pN)

gibi bir şey elde etmez miyiz? O halde gelin kendimizi her seferinde funcall ve apply yazmaktan kurtaralım:

(defun get-method (nesne mesaj)
  "Bu nesne icin verilen mesaja göre ilgili metodu döndür."
  (funcall nesne mesaj))

(defun send (nesne mesaj &rest args)
  "Mesaji cagirmak icin gerekli metodu elde ettikten sonra
   buna gerekli argümanlari verip sonucu döndür."
  (apply (get-method nesne mesaj) args))

Bakalım mekanizma nasıl işliyor:


CL-USER> (send *hesabim* 'ad)
"fz'nin banka hesabi"
CL-USER> (send *hesabim* 'bakiye)
100
CL-USER> (send *hesabim* 'yatir 100)
200
CL-USER> (send *hesabim* 'bakiye)
200
CL-USER> (send *hesabim* 'faiz)
218.0
CL-USER> (send *hesabim* 'faiz)
237.62
CL-USER> (send *hesabim* 'faiz)
259.0058

Oturduğum yerden para kazanmakla kalmadım, ufak ve sevimli bir nesne elde ettim. Pardon "closure". Ya da bir tür nesne. İsmin ne önemi var (bazıları için var tabii, buzzword şeklinde ama şimdilik bununla işimiz yok). Bir taşla kuş katliamına gittikçe yaklaşıyoruz.

Şimdi yukarıdaki durum, yukarıdaki sözdizimi bazı Lispçileri rahatsız etmiş olabilir ve Norvig'in sorduğu gibi şu soruyu sormuş olabilirler:

- Bir sürü hesap olsa elimizde ve bunların bakiyelerini öğrenmek istesek bunun için geleneksel Lisp tarzı olarak (mapcar 'bakiye hesaplar) gibi bir şey kullanamayacak mıyız yani?

Mevcut durumda maalesef şöyle yazmak zorunda kalıyoruz:

(mapcar #'(lambda (hesap) (send hesap 'bakiye)) hesaplar)

Bu durumu düzeltmek, kolaylaştırmak gene biz Lisp programcılarının elinde. Mesela cek metodunu şu şekilde yazsak:

(defun cek (nesne &rest args)
  "cek ismini nesneler üzerinde calisan generic bir fonksiyon 
   olarak tanimla."
  (apply (get-method nesne 'cek) args))

ve bir de yukarıdaki "tarz"ı denesek:

CL-USER> (cek *hesabim* '10000000)
YETERSIZ-BAKIYE
CL-USER> (cek *hesabim* '195)
64.0058


Biraz para kaybettik ama olsun, Lisp tarzına biraz daha yaklaşabilmek için buna değer doğrusu.

Sınıfsız OO Bir Ütopyadır

Okurun aklına şu gelebilir: her seferinde bir nesneye ihtiyaç duyduğumda gidip öyle defun, lambda filan mı kullanacağım uzun uzun, hani OO programlama yapıyorduk, nerede sınıflar? Sınıf tanımlama mekanizmasını göster bana.

Gayet haklı, makul bir talep! Bir tür sınıf tanımlama yapısının olması şart. Yine elimizde CLOS (Common Lisp Object System) olmadığını var sayıp devam edelim ve Common Lisp'teki "macro"ların gücünü kullanalım (kemerlerinizi bağlayın!):

(defmacro define-class (class inst-vars class-vars &body methods)


  "Nesneye yönelik programlama icin sinif tanimlama macrosu."
  ;; constructor ve metodlar icin generik fonksiyonlari tanimla
  `(let ,class-vars
     (mapcar #'ensure-generic-fn ',(mapcar #'first methods))
     (defun ,class ,inst-vars
       #'(lambda (message)
           (case message
             ,@(mapcar #'make-clause methods))))))

(defun make-clause (clause)
  "define-class'tan gelen mesaji case yapisinin icine yerlesecek sekle cevir."
  `(,(first clause) #'(lambda ,(second clause) .,(rest (rest clause)))))

(defun ensure-generic-fn (message)
  "Eger daha önce tanimlanmadiise mesaj icin nesneye yönelik
   bir 'dispatch' fonksiyonu tanimla."
  (unless (generic-fn-p message)
    (let ((fn #'(lambda (object &rest args)
                  (apply (get-method object message) args))))
      (setf (symbol-function message) fn)
      (setf (get message 'generic-fn) fn))))

(defun generic-fn-p (fn-name)
  "Bu generic bir fonksiyon mu."
  (and (fboundp fn-name) 
       (eq (get fn-name 'generic-fn) (symbol-function fn-name))))



Kısa ama yoğun bir Lisp kodu. Tek tek açıklamakla uğraşmak yerine söz konusu makronun açılımına bir göz atmayı tercih edeceğiz:

CL-USER> (macroexpand-1 '(define-class hesap 
			  (ad &optional (bakiye 0.00))
			  ((faiz-orani 0.09))
			  (cek (miktar)
			   (if (<= miktar bakiye)
			       (decf bakiye miktar)
			       'yetersiz-bakiye))
			  (yatir  (miktar) (incf bakiye miktar))
			  (bakiye () bakiye)
			  (ad () ad)
			  (faiz ()
			   (incf bakiye (* faiz-orani bakiye)))))

(LET ((FAIZ-ORANI 0.09))
  (MAPCAR #'ENSURE-GENERIC-FN '(CEK YATIR BAKIYE AD FAIZ))
  (DEFUN HESAP (AD &OPTIONAL (BAKIYE 0.0))
    #'(LAMBDA (MESSAGE)
        (CASE MESSAGE
          (CEK
           #'(LAMBDA (MIKTAR)
               (IF (<= MIKTAR BAKIYE) (DECF BAKIYE MIKTAR) 'YETERSIZ-BAKIYE)))
          (YATIR #'(LAMBDA (MIKTAR) (INCF BAKIYE MIKTAR)))
          (BAKIYE #'(LAMBDA () BAKIYE))
          (AD #'(LAMBDA () AD))
          (FAIZ #'(LAMBDA () (INCF BAKIYE (* FAIZ-ORANI BAKIYE))))))))
T

Dikkat edecek olursanız, macroexpand-1 ile gerçekleştirilen açılımdaki "(defun hesap..." ile başlayan kısım ta en başta bizim yazdığımıza çok benziyor.

Artık elimizde yeni yeni sınıflar tanımlamak için define-class diye bir yapı var ve bunu kullanabiliriz:

CL-USER>(define-class hesap 
	     (ad &optional (bakiye 0.00))
	     ((faiz-orani 0.09))
	    (cek (miktar)
		 (if (<= miktar bakiye)
		     (decf bakiye miktar)
		     'yetersiz-bakiye))
	    (yatir  (miktar) (incf bakiye miktar))
	    (bakiye () bakiye)
	    (ad () ad)
	    (faiz ()
		  (incf bakiye (* faiz-orani bakiye))))

HESAP

Bakalım çalışacak mı? Madem bir sınıf tanımladık bundan bir "instance" oluşturalım ve oluşan "nesne"yi de *diger-hesap* isimli bir değişken ile gösterelim:


CL-USER> (setf *diger-hesap* (hesap "fz'nin diger hesabi" 1000))
#
CL-USER> (ad *diger-hesap*)
"fz'nin diger hesabi"
CL-USER> (bakiye *diger-hesap*)
1000
CL-USER> (faiz *diger-hesap*)
1090.0
CL-USER> (cek *diger-hesap* 3456345896340598)
YETERSIZ-BAKIYE
CL-USER> (cek *diger-hesap* 99)
991.0


Artık elimizde sınıfları, sınıf değişkenlerini ve sınıf metodlarını tanımlamak için bir yapı mevcut. OO dünyasında geçen "encapsulation" sağlanmış durumda (kolaysa closeru'ın içine girip müdahale etmeye kalkın ;-) ve buna ek olarak "generic" fonksiyon yaklaşımımızdan ötürü tanımladığımız metodlar, tamamen isimleri aynı kalmak sureti ile bambaşka nesneler için de tanımlanıp çağrılabilirler. Söz gelimi define-class ile "silah" isimli bir sınıf ve buna özgü bir cek metodu tanımlayıp ardından *silahim* diye bir şey yapıp (cek *silahim*) çağırmamız mümkün olabilir.

Bitirirken - Eve Dönüş

Tabii ki bir OO sisteminde yukarıdakilerden daha fazlası gerekir, söz gelimi hiç miras alma yani "inheritance" mekanizmasına ve başka detaylara değinmedik, çoklu miras alma yani "multiple inheritance" gibi girift konuların yakınından dahi geçmedik.

Bu kısa makalenin amacı Common Lisp'i biraz daha tanıtmak, dilin esnekliğini göstermek idi. Bunun için Norvig'in örneklerinden faydalandık ve eğer Common Lisp içinde herhangi bir OO programlama yapısı olmasa idi bunu geliştirmeye nasıl başlardık, bunu birkaç örnek üzerinden inceledik.

Common Lisp ile ciddi anlamda ve gayet sofistike şekilde nesne yönelimli programlamayı merak eden okur tam teşekküllü CLOS (Common Lisp Object System) sistemini öğrenip OO programlamanın harika dünyasına ilk adımları atabilir.

Common Lisp'te nesne yönelimli programlama yapmamızı sağlayan CLOS ile ilgili detaylı bilgiler kaynakçadaki eserlerde mevcuttur.

Kaynakça




Emre "FZ" Sevinç
16 Ekim 2005
İstanbul


Not: Yazının özgün adresi burasıdır.

Görüşler

0
ttk
Yine mi Lisp ?
Ayrıcana niye Ali değil de Alice ?

Ali bak bu Lisp, bazıları onu çok sever.
Ali Lisp'i çok sev (ya da terket aanadın mı.)

:)

0
darkhunter
:)
Ve yazar psikolojik çözülmelerini daha fazla içinde tutamaz, salıverir ortama...
0
FZ
Çünkü Alice Harikalar Diyarında bana hep daha çok şey çağrıştıragelmiştir. Metafor üstüne metafor, paradoksal durumlar, abzürd görünen şeylerin anlamlı şeylerle bağlantısı... Yazarının garipliği, tüm hikayenin garipliği. Sıradan sözcüklerle yaratılan karmakarışık dünyalar. Tıpkı sıradan ve basit görünümlü fonksiyonlarla yaratılan karmaşık sistemler gibi. Ya da mesela kendinden sonra gelen pek çok yazarı ve eserlerini etkilemiş oluşu. Efsane eserlerden biri mertebesine yükselişi. Küçücük bir çocuğun da, üst düzey bir bilimadamının da okuyup bambaşka şeyler görebilmesi... Ya da burada Common Lisp'ten bahsettiğimizde gündeme bazı diyalogların o spiral kaotik hali...

"But I don't want to go among mad people," Alice remarked. "Oh, you can't help that," said the Cat: "we're all mad here. I'm mad. You're mad."


http://en.wikipedia.org/wiki/Alice's_Adventures_in_Wonderland.

Bu arada yazının kendisi ile, orada anlatılanlarla ilgili sorusu, eleştirisi olan, ya da izlenimlerini paylaşmak isteyen?
0
ttk
Lisp'i şu anda sökmeye çalışan ve her Lisp ile ilgili yazı da "vay bea" tarzı tepki veren bir FM üyesi olarak yine aynı şeyleri demeyeyim diye işi biraz dalgaya vurdum :) Başka bir dil ile böyle bir işi yapmak ne derece mümkün, acaba var mı başka böyle bir bilgisayar dili bilen varsa söylesin diyeyim kısaca.
0
Ragnor
Hah tam soracağım soruyu sormuşsun. Bende bunu öğrenmek istiyorum. Emin değilim ama C'de galiba struct kullanarak benzer birşeyler yapabiliyorduk. Yinede bu konuda söyleyebileceğiniz birşey var mı?
0
bm
FZ'nin gosterdigi (ve farkettigi icin heyecenlandiran) su: sadece lexical closure kullanarak, C'deki structlar ayarinda bir nesne uretmekle kalmadik bir de bu tip nesneler uzerinde calisan metodlar tanimladik. Bu da yetmedi, diger dil ozelliklerinden ayirdedilemeyen bir define-class ekledik dilimize.

Bunu yaparken lecixal closure ve macro ozelliginden baska bisey kullanmadik. Yani icinde sadece fonksyonlar ve macrolar olan C'ye, structlari ekleyebilme ve bunlarin sonradan eklenmis oldugunu belli etmeme egzersizi olarak dusunebilirsiniz belki. (Common Lisp'te defstruct ve defclass var tabii. C'de bunu bu sekilde yapmak mumkun degil, cunku macrolar gucsuz, lambda olmadigi icin buradaki gibi closure filan da yapilamiyor. Bunlar konu disi.)

Bu arada ekleyeyim, memoization yazisina gelen cevaplarda ornek olarak Javascript kullanan arkadas (rumuzunu unuttum kusura bakmasin) bu lexical-closure/nesne benzerligini gayet guzel sezmisti. Yani biraz konulari anladiktan sonra bu tip seyler ise yatkin insanlar tarafindan sezilebiliyor. Bu denemenin amaci elbette "lisp'e nasil nesne eklenir" degil, lexical closure olan bir dilde nasil nesne kilikli seyler de _zaten vardir_, bunlari lisp'te olan sozdisimsel soyutlama (syntactic abstraction) imkanlariyla nasil kullanabiliriz diye basitce gostermek.

Bu tip seyleri seviyrosaniz burada yazilarinin tercumeleri yayinlanan Graham'in bir kitabinda[1] bunun kalitimli filan bir ornegi de var. Boyle dilin kendisini minciklamak Guido, Sun, Microsoft gibilerin 'en son dil ozelligi' cikartmasini beklemekten (ve sonra heyecanlanmaktan) daha zevkli olsa da yeni baslayanlar icin biraz kafa karistirici olabilir. Kafasi karisanlari Lisp Calisma gurubuna alalim lutfen.

[1] Kitap acik http://www.paulgraham.com/onlisp.html


0
FZ
Bu arada ekleyeyim, memoization yazisina gelen cevaplarda ornek olarak Javascript kullanan arkadas (rumuzunu unuttum kusura bakmasin) bu lexical-closure/nesne benzerligini gayet guzel sezmisti. Yani biraz konulari anladiktan sonra bu tip seyler ise yatkin insanlar tarafindan sezilebiliyor. Bu denemenin amaci elbette "lisp'e nasil nesne eklenir" degil, lexical closure olan bir dilde nasil nesne kilikli seyler de _zaten vardir_, bunlari lisp'te olan sozdisimsel soyutlama (syntactic abstraction) imkanlariyla nasil kullanabiliriz diye basitce gostermek.

Common Lisp ve Bir Optimizasyon Tekniği: Memoization başlıklı yazının altına söz konusu yorumu yazan yetgin takma isimli üyemizdi. Güzel bir tartışma ve fikir alışverişi olmuştu.

Bu tip seyleri seviyrosaniz burada yazilarinin tercumeleri yayinlanan Graham'in bir kitabinda[1] bunun kalitimli filan bir ornegi de var. Boyle dilin kendisini minciklamak Guido, Sun, Microsoft gibilerin 'en son dil ozelligi' cikartmasini beklemekten (ve sonra heyecanlanmaktan) daha zevkli olsa da yeni baslayanlar icin biraz kafa karistirici olabilir. Kafasi karisanlari Lisp Calisma gurubuna alalim lutfen. [1] Kitap acik http://www.paulgraham.com/onlisp.html

Kafa patlatmak ve birlikte öğrenmenin getirdiği avantajlardan faydalanmak isteyenleri bekleriz:

Lisp Çalışma Grubu, posta listesi, ilgili GMANE sayfası, posta listelerini sevmeyenler için ağaç yapılı mesaj listesi ve blog tarzı arayüz.

Bu arada merak edenler olabilir belki, yani Bilgi Ü. adı geçiyor ama üyelerimiz arasında İTÜ Bilg. Müh.den insanlar, profesyonel yazılım geliştiriciler, başka şirketlerde çalışan programcılar, bilgisayar bilimleri bölümlerinden asistanlar, deneyimli Lispçiler, FM üyeleri, vb. var. Yani katılıma açığız.
0
FZ
Son toplantının notları.
0
kesken
Başka bir dil ile böyle bir işi yapmak ne derece mümkün, acaba var mı başka böyle bir bilgisayar dili bilen varsa söylesin diyeyim kısaca.
tum diller ile oop programlama yapilabilecegi kanaatindayim, makine dilinde dahi. oop dilden bagimsiz bir durumdur, hangi dilin kullanildigi farketmez, dilin yapisinin size ne kadar yardimci olacagi baska bir husus tabi.
0
ttk
Merhaba
Problem de burada zaten, bazı programlama dillerinde kolayca yapılabilen işleri (burada görüldüğü gibi) bazı başka dillerde yapmak için bayağı bir uğraşmak gerekebilir, adeta işin teoride kalmasına sebep olabilecek derecede zorluklarla karşılabilir değil mi ?

Programlama dilinin tasarlanışından gelen meselelere yaklaşım tarzı, oldukça zorlu işlerin bazı programlama dillerinde tahmin edilemeyecek derecede kolay bir biçimde yapılabilmesine imkân sağlayabiliyor.
0
FZ
dilin yapisinin size ne kadar yardimci olacagi baska bir husus tabi

Çok önemli bir husus tabii.

Yoksa yani dillerin (çoğunun) birbirlerine Turing-tamlık bakımından denk olduğunu belirtmek pratik olarak çok bir şey ifade etmiyor.

Bazı şeyler pratikte fark ediyor yani.
0
kesken
acaba diyorum boyle birseye gercekten gerek var mi? yani oop programlamanin benim icin ifade ettigi iki sey var hayatta:

* yeniden kullanilabilir kod
* icerikten bagimsiz kod

bana bu iki olanagi saglayan herhangi bir modelleme kabulumdur. nesnel modelleme ile gercek hayati modelliyoruz, peki niye lisp ile nesnel modellemeyi modelliyoruz, direkt gercek hayati modellesek ya! boylece lisp'in bize sundugu farkli dusunme olanaklarini elimizin tersiyle geri itmesek.
0
FZ
Yeniden kullanılabilirlik önemli bir mevzu. Miguel de Icaza'nın çok sağlam eleştirisi vardır UNIX ve GNU/Linux dünyasına bu bakımdan. Aptalca bir emek israfından bahseder somut ve büyük bazı kod tabanlarını göstererek.

"Lisp ile nesnel modellemeyi modellemek" lafını pek anlayamadım ben. Bahsettiğimiz OOP tarzı yaklaşımının nasıl uygulanabileceği idi, yani iki katmanlı bir şey değil, OOP'yi modellemek değil, doğrudan OOPnin kendisi.

Bu şekilde Lisp'in bize sunduğu farklı düşünme olanaklarını elimizin tersi ile itmiş olmuyoruz ki. Lisp içinde fonksiyonel tarzda programlama, OOP tarzı programlama, mantık programlama tarzında şeyler yapmak mümkün olabiliyor. OOP kullanılan yöntemlerden sadece biri.
0
FZ
Norvig'in kitabının faydalandığımız bölümde bir de tavsiye var, Steele'nin Lambda: The Ultimate Declarative makalesini okumanın çok faydalı olacağı söyleniyor:

http://library.readscheme.org/page1.html

Yukarıdaki adreste diğer makaleleri de bulmak mümkün.
0
Geryon
"Başka bir dil ile böyle bir işi yapmak ne derece mümkün, acaba var mı başka böyle bir bilgisayar dili bilen varsa söylesin diyeyim kısaca."

walla sizinde bildiğiniz gibi "deli" çok :) NaN masm32 için oop assembly macroları yazdı.(OO Assembly'ımız de oldu yupieeee)
inheritance,override,polymophic fonksiyonlar vb... destekliyordu. Fakat ben hiç kullanmadım, iyi mi kötü mü bilemiyorum. artık masm32 paketi ile beraberde geliyor.
Ayrıca NaN'ın sitesi
0
darkhunter
Bi dönem TP altında OO yazmıştım, proje gibi birşey için... Zaten başlıkta belirtildiği gibi, nesne yönelimli bir dil yoksa elimizde basic ile de OO ilüzyonları yapabiliyorsunuz... O değil de ben bayadır düşünüyorum, kaçımız pratiklik söz konusu olunca OO'ya yoğunlaşıyoruz? Kendi adıma cevabım düşünerek işin içinden çıkamayana kadar OO'nun yanından geçmediğim yönünde :)
0
ttk
Merhaba

Bence gözden kaçan nokta az bir uğraşla yukarıda varılan sonuç. Yeterince uğraştıktan sonra işin ustası olanlar kullandıkları dilde bu işi yapabilirler tabii.

Bu arada, OOP'u hemen hiç kullanmazdım ama bir .Net programında kullandım, baktım çok işe yarıyor. Bir formu temel form yapıp diğer formları onun mirasçısı yapınca normalde her sayfada tek tek eklenmesi gerekecek şeyleri ana forma uygulamak çok daha pratik oldu.
Bir şeyi kullanmadan kolayca haledebileceğimiz bir işte zoraki o şeyi kullanmaya çalışmak büyük sıkıntı, ama gerçekten lazım olduğu yerde kullanınca da büyük kolaylık oluyor. Arz-tabela kanunu :)
0
tongucyumruk
Bu lispçiler iyiden iyiye kontrolden çıkmaya başladı. Bunların beline sopa lazım. Ne demek kardeşim "elinizin altında oop yoksa". Tabii siz kalkıp fosil bir dille kod yazmaya çalışırsanız böyle uğraşırsınız. Adam yapmış hazırını. Java yapmış, Eclipse yapmış Visual Studio.Net yepmış. Tıklıyorsun yazıyorsun. Neymiş efendim "Closure" hadi oradan... Şaka bir yana sadece bir makro kullanarak böylesi bir sistemi geliştirmek bende olmayan şapkamı çıkartmaya çalışırken yanlışlıkla zaten az olan saçlarımı yolma isteği uyandırıyor.
0
FZ
:)

Common Lisp gerçekten büyük esneklik sunuyor.

Bu arada gezinirken bir Python programcısının 2003 yılında yazdığı aklı başında makaleler fark ettim O'Reilly'de: Advanced OOP: Multimethods yazısında mesela CLOS'tan haberdar olduğunu belli ediyor ancak bunu sanki bir eklentiymiş gibi yazmış oysa CLOS dediğimiz şey Common Lisp'in bir parçası, dil tanımında yer alıyor. Neyse, en azından doğru yere göndermede bulunmuş David Mertz arkadaşımız. Tabii şu da var Python'cular o makalede anlatılan mevzuyu "advanced OOP" diye okurken orta seviyeli Practical Common Lisp gibi bir kitaptan Lisp öğrenen biri en baştan öğreniyor mesela.

Bir diğer makale, A Primer on Python Metaclass Programming ise Common Lisp ve MetaObject Protocol mevzusunu üç beş bilen biri için eğlenceli bir makale, Python'cuların nelere nasıl baktıklarını gösterme açısından. Mertz'in bu makalede The Art of MetaObject Protocol'e değinmemesi ise herhalde bir unutkanlık ya da cehalet olsa gerek.

Mertz'in bir başka dikkat çekici makalesi Advanced OOP: Declarative Programming and Mini-Languages da belki Graham'ın neden Python hackerlarına iyi gözle baktığının bir işareti olabilir. Dil içinde mini-dil geliştirmeyi ve kullanmayı vurgulamanın yanısıra yine dilin dişine çıkmadan bambaşka bir dili entegre etmenin de bir özeti.

O makaledeki Prolog kullanalım tarzı örnek de yine Lisp okurlarına yabancı değil, makalenin yazıldığı tarihten 10-15 yıl önce Lisp kitapları okuyan insanlar zaten bir süre sonra Lisp'te nasıl Prolog yapacaklarına dair bölümlerle karşılaşıyorlardı.

Bir kez daha görüyorum ki, Lisp tapınağında belli bir süre geçirenler için diğer dillerdeki bazı şeyleri anlamak ve kıyaslamak daha kolay oluyor. Şimdi sanırım ESR'nin ne demek istediğini daha iyi anlamaya başlıyorum.
0
myavuzselim
Makrolari abartmayalim!!!

Ama eger sunu saglayan bir makro yazabilirseniz lisp'i opup basima koyarim:
(macroexpand '('(a b c d e) i)) -> (nth i '(a b c d e))

Dili degistirebilmek budur iste!

Yukaridakinden lisp makrolarina burun kivirdigim anlasilmasin. Ayni isi (ve benzerlerini) bitirme tezi olarak haskell uzerinde yapmam gerekiyor. Sadece bunun lispte makrolar vasitasiyla yapilabilip yapilamayacagini merak ettim, birilerini gaza getirmeye ugrasiyorum. Ama yapilabilecegini de pek sanmiyorum hani :)
0
bm
Iyi de onu oyle yaparsak hakikaten dili bozuyoruz. Reader'i degistirerek bunu yapmak kabil olmali ama butun iki elamanli sabit listeleri nth haline dondurmemek icin ek birsey dememiz lazim. Yani 'suradan itibaren bu okunan common lisp syntaxinde degil' diyebilmemiz lazim. Cl-infix [1] infix artimetik okumak icin #i kullanir mesela. Oyle de olabiliyorsa comp.lang.lisp sizi bekliyor (belki burada musteri cikar? yahut ben yanlis soylemisimdir?).

[1] http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/code/syntax/infix/infix.cl
0
FZ
Vallahi Lisp'i öpüp başınıza koymak için çok saçma bir örnek önermişsiniz. O dediğiniz şey olursa saçma bir şey olur, şu sebeple ki temel liste temsilini bozmuş olursunuz, bu sefer de o gösterimi kazanmak için başka bir şey yapmanız gerekir. Biraz mantık yürütürseniz ne demek istediğimi anlayacaksınız.

Eğer siz Lisp'teki makroları duyunca yukarıda verdiğiniz gibi bir örnek düşünüyorsanız o zaman ya yeterince okumadınız ya da hakikaten okuduklarınızın bir kısmını yanlış anladınız.

Bu arada eğer derdiniz önce listeyi yazayım sonra indisi yazayım ise, bu daha makul ve yapılabilir bir istek. Zaten hazır yapılmışı var, elt, olmasa da yapması zor değil.

Burada mesele istediğiniz şeydeki problemi anlıyor musunuz önemli olan o. Yaptığınız şey, mantıken bir yan etkiye yol açıyor ve bu yan etkiyi gidermek için başka bir şey yapmanız gerekir. Eğer bunu fark ederseniz o zaman daha verimli bir tartışma olabilir herhalde. Yoksa yani bak şu yapılabilir mi, yapılabilir meselesi değil o.
0
myavuzselim
Galiba yukarida bayagi bir :) eklemeyi unutmusum :)
Bastaki begenmez tavir saka niyetineydi. Son paragrafin basinda bunu belli edeyim demistim, ama tekrar okuyunca goruyorum ki olmamis. Bunu da benim anlatim beceriksizligime verin :)

Yukaridaki ornekde bu seyin onune quote gelmesi talihsizlik olmus.
Makrolari unutun. Sizce lisp'de bunun boyle yapilmis olamamasi icin bir neden var mi? Ben su anda goremiyorum. Eger bir listeye bir dogal sayi uygulayacak olsak, lisp her zaman hata mesaji veriyor. Bu bosluk doldurulamaz mi?

Bunun gereksiz bir ozellik oldugunu dusunebilirsiniz. Ben de dusunmuyor degilim. Fakat bunun teorik bir anlami var: hersey fonksiyondur. Ayrica sadece bu da degil, diger veri yapilari da fonksiyon olabilmeli. Mesela
(defvar *my-hash* (create-hash))

...

(progn 

  (put *my-hash* 'key 7)

  (*my-hash* 'key)) --> 7

Ya da benzeri seyler (mesela (data 'slotname) -> slotvalue gibi, bu zaten lispte var galiba, tam emin degilim simdi). Fakat lisp'de "hersey fonksiyondur"dan cok "hersey veridir" daha gecerli gordugum kadariyla. Sadece bu isin lisp uzerinden yapilip yapilamayacagini/nasil yapilacagini tartismaya acayim dedim :) Fakat bunu sonucta lisp'de degil de haskell'de yapmaya calismam gerek. Bu da haskell compiler/interpreter'larini kurcalamadan olamayacak birsey gibi gorunuyor.
0
FZ
Eger bir listeye bir dogal sayi uygulayacak olsak, lisp her zaman hata mesaji veriyor.

Listeye doğal sayı uygulamak ne demek?

Elinizde bir liste, bir de doğal sayı var. Bunları hangi işlem içinde kullandığınızı söylemenizi bekliyor sizden derleyici. Tıpkı C, C++, Java, C# gibi dillerde bir array ve bir doğal sayıyı [] operatörü ile bir araya getirerek derdinizi anlatmanız gibi.

Bu bosluk doldurulamaz mi?

Bunun boşluk olduğunu nereden çıkarıyorsunuz?

Common Lisp'te keskin bir kod/veri ayrımının olmadığı doğrudur, bunun sebebi de fonksiyonları bir araya getirme şeklinin yine bir veri yapısı olan listelere benzer olması ve dolayısı ile makrolar, vs. ile kodun esnek şekilde kullanılabilmesi.

Ancak her şey veridir, ya da her şey fonksiyondur lafı bana çok bir şey ifade etmiyor, en genel anlamda evet her şey bilgisayardaki veridir ikilik sistemdeki bit dizisidir filan ama bir programlama dili bağlamında bunu ayırıyoruz. O yüzden siz, veri yapıları fonksiyon olabilmeli derken tam olarak amacınızı anlayamıyorum. Bütün mesele bir veri yapısındaki bir elemana ulaşmak için bir fonksiyon ismi yazmaktan kurtulmak mı?

İlla bu isteniyorsa, (spekülasyon moduna geçildi, alçaktan uçuyoruz) belki sisteme biraz müdahale edilip listenin ilk elemanı basit veri tiplerinden bir tanesi ise, diğer eleman(lar) da bunun içindeki bir şeye erişmek için kullanılabilecek uygun türde değerler taşıyan şeyler ise o zaman geriye kalan elemanları al ve ilk elemandaki ilgili bilgiye ulaşıp bunu döndür gibi bir şey yapılabilir. Bu şekilde sözdizimindeki birörnekliği (uniformity) kaybetmiş oluruz, ilk rahatsızlık benim açımdan burada başlıyor. Üstelik kod okurken, yani special var. konvansiyona uygun şekilde *...* şeklinde yazıldı ise anlamak zor değil ama let ile bağlanmış bir değişken ise o zaman bunu isimden çıkarmak yani bir öyle bir böyle sürekli bakış açımı değiştirmek, pek de okumayı ve algılamayı kolaylaştıran bir şey değil. Tabii bunlar benim ilk aklıma gelenler, böyle bir değişikliğin yol açabileceği başka durumlar da olabilir, bunların avantajları/dezavantajları şu anda çok iyi analiz edebildiğim şeyler değil.

Bu arada yukarıdaki kodda, create-hash yerine make-hash-table demeniz gerekiyor. "Hash table"a bir şey yerleştirmek için put değil de başka bir şey demeniz lazım, buradan bakabilirsiniz. Common Lisp'teki hash table konusu ile ilgili genel bilgi için ise buraya bakabilirsiniz. Ayrıca progn kullanmışsınız, ona da gerek yok.
0
bm
Pekiyi obur baslikta cenem dustugu icin buraya uzun yazamiyorum. Sanslisiniz yani! Size daha iyi anlatan bir adamdan benzer konuda birseylere link vereyim: http://groups.google.com/group/comp.lang.lisp/msg/8116f94bd0a22e74
0
myavuzselim
Evet, orada da buna deginilmis: array/list gibi veri yapilari ile bir index alip deger donduren fonksiyonlar arasinda (anlam bakimindan, performans ayri bir konu tabi) buyuk bir fark yok. O yuzden neden bu veri yapilarini boyle bir fonksiyon olarak gormeyelim gibi bir soru sorulabilir.

Tabii burada daha onemli bir soru var: neden gorelim? :) O da baska bir mesele.
Görüş belirtmek için giriş yapın...

İlgili Yazılar

Microsoft ve Lisp: Ya da .NET CLR Garbage Collector Hangi Dilde Yazıldı?

FZ

USENET comp.lang.lisp forumundaki eğlenceli bir mesaj dikkatimi çekti paylaşmak istedim.

Meğer meşhur .NET platformunun ana bileşenlerinden biri olan CLR (Common Language Runtime) sisteminin çöp toplayıcısı (garbage collector) Lisp ile yazılmış.

Sağlam Lisp "hacker"larından olan ve bir süredir MS için çalışan, CLR'nin baş mimarlığını yapan Patrick Dussud'un yazdığı Lisp kodu daha sonra bir Lisp'ten C'ye dönüştürücü ile C'ye dönüştürülmüş ve bu kod da MS'deki bir stajyer programcı tarafından "temizlenip" derlenip piyasaya sürülmüş.

Lisp ve .NET konusu açılmışken: Her iki dünyadan da vazgeçmek istemeyenler için enteresan projeler çıkmaya başladı: L Sharp .NET (C#'tan çok daha eğlenceli ;-), RDNZL ve FOIL.

MIT LispM Kaynak Kodunu Kamuya Açıyor

FZ

MIT, LispM kaynak kodunu BSD tarzı bir lisans ile kamuya açıyor. Bu şu demek: Lisp Machines sistemlerinin temel bileşeni artık özgür. BSD lisansı sayesinde de insanlar bundan istedikleri gibi faydalanabilirler.

Pascal Costanza'nın Çok Dik Başlı Lisp Rehberi

FZ

Uzunca uğraşlardan sonra Pascal Costanza'nın dik başlı (!) Lisp kılavuzunu Bilkent Bilg. Müh. bölümü öğrencilerinden Hayrettin Gürkök'ün çevirisi ile anadilimizde yayımlama imkanına kavuştuk. AOP yani Aspect Oriented Programlama mefhumunu Common Lisp'e kazandırmış olan (ya da Debiancılar için: Debian aspectl paketleri) Costanza'nın bu yazısının Lisp heveslilerinin işine yarayacağını ümit ediyoruz.

Çevirinin özgün adresi http://ileriseviye.org/arasayfa.php?inode=costanza-lisp-guide.html'dir. Emeği geçen herkesin eline sağlık. Afiyet olsun...

Hangi Common Lisp?

zekzekus

Daniel Weinreb, buradan erişilebilecek şekilde, Common Lisp gerçekleştirimleri (implementasyonları) ile ilgili bir inceleme yapmış. İncelemeye konu olan Common Lisp gerçekleştirimlerinin sorumluları kendi gerçekleştirimlerini anlatmışlar. "Nedir bu Lisp? Ortada bir sürü Lisp var, hangisini seçmeliyim?" diyenler için özellikle az bilinen Common Lisp gerçekleştirimlerini de içermesi açısından güzel bir kaynak.

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)