2008年7月21日星期一

荀子性惡論

最近在讀普通心理學(Atikinson and Hilgard's Introduction to Psychology),閒暇之餘,兼讀一點荀子,兩相參照之下,對過往我們所認知的「性惡論」一說,有些新的體會。
節錄一段荀子性惡篇的原文如下:

人之性惡,其善者偽也。
今人之性,生而有好利焉,順是,故爭奪生而辭讓亡焉;生而有疾惡焉,順是,故殘賊生而忠信亡焉;生而有耳目之欲,有好聲色焉,順是,故淫亂生而禮義文理亡焉。
然則從人之性,順人之情,必出於爭奪,合於犯分亂理,而歸於暴。
故必將有師法之化,禮義之道,然後出於辭讓,合於文理,而歸於治。用此觀之,人之性惡明矣,其善者偽也。
...下略...

回想過去的學習,我們對傳統思想的瞭解,其實多半流於表面。若是向現在的國高中生問起,先秦儒家的思想,我敢說,十個人中,有十個都會告訴我們,至聖孔子講「吾道一以貫之」,流傳至戰國時,分為主「性善」的孟子,以及主「性惡」的荀子兩派--這也是過去教科書上的標準答案,我想,即便是現在,應該也差不了多少。
不過當我們再問起孟子的「性善論」與荀子的「性惡論」的內容時,大多數人大概只能講出孟子的「側隱之心,人皆有之」,而講到荀子,多半還是一句「人性本惡」,便就此了結。
這種對儒家學派的刻板印象,從過去便一直拘束著我們的想法及觀點。
然而如果更深入去看荀子,孟子的學問,而不是只知道教科書中簡單-或者應該說「粗糙」的-「善惡對立」的說法,我們會發現荀子「性惡」與孟子的「性善」,所指涉的「性」,在根本上就有所不同。
簡單一點來說,荀子的「性」指的是人「天生」的「欲望」,而孟子所指的「性」,則是人「天生」的「情感」。
而荀子的「性惡說」,若是要更正確的描述,應該命名為「後天論」,而非「性惡說」。
荀子與孟子所爭論的問題,實應重新表述為:「道德仁義」究竟是先天具有的,或是後天形成的?
回過頭來看一下荀子的原文:
今人之性,生而有好利焉…生而有疾惡焉…生而有耳目之欲,有好聲色焉…

荀子所描述的「人之性」,都是屬於生物學上的「欲望」,是生物為了生存所必需的競爭能力。這種能力,本來並無所謂「善」「惡」之分別,更精確的說,與普世所認知的「惡」的意義,其實相去甚遠。在這裡,我比較認同陳修武在荀子-人性的批判一書中的說法:荀子的性惡論,其本質應是「告子」的「性無善惡」。
如果由「先天」「後天」的觀點來理解荀子的學說,我們也可以發展出另外二個觀點:
  1. 荀子,孟子之爭,其實並不如教科書所說的,至宋元而定於一尊。就我所知,宋代理學朱陸之爭,有一部分便是關於先天後天之爭。(據聞,當時陸九淵與朱熹爭到面紅耳赤時,甚至差點講出「先王所讀何書?」一句,以非難朱熹後天論點。)

  2. 一般以朱熹納「孟子」於四書之中,作為孟子性善說勝出之表徵。但從以上的觀點看來,朱子之學,其實已吸納了荀子的「性惡說」在內,而非純然的孟子之教。

再回頭來看看,荀子的「性惡」之說,真正嚴格討論起來,有兩個問題存在:
  1. 荀子將「性」定義為人天生就具有的特質。此種特質,事實上包含了「欲望」與「情感」兩部分,但荀子全然不提「情感」的部分。

  2. 正如陸子鵝湖之會所提「先王所讀何書?」,荀子無法解釋若一切均為後天「偽」之,那「聖人化性而起偽」是基於什麼?

其中第二個問題,其根源還是來自於第一問。基本上,若是不把先天的「情感」也納入考量之中的話,是無法解決「人性論」的爭議的。
從現代心理學的發展來看,先天與後天,並不是對立的,而是在交互作用下發揮其影響力。至於人性是善,或是惡?
目前還是一個懸而未決議題。在我個人而言,孟子所言:
蓋上世甞有不葬其親者,其親死則舉而委之於壑。他日過之,狐貍食之,蠅蚋姑嘬之。其顙有泚,睨而不視。夫泚也,非為人泚,中心達於面目。蓋歸反虆梩而掩之,掩之誠是也。則孝子仁人之掩其親,亦必有道矣。
最能表情感之所由。
人天性如此,又怎能輕言其惡?
[註]荀子書中所用「偽」之意義,並非虛假不真之意,而是指「人為」之意,亦即後天影響者。

2008年7月2日星期三

回溯相容真是個地獄...T.T

這是一篇抱怨文。
Obj-C 2.0的語法相當的方便,當開發目標放在10.5以後的系統時,property,fast enumration等新增語法,
確實可以加快開發的速度。再加上Cocoa binding等技術,在10.5上開發真的是相當輕鬆-如果只打算在10.5上跑的話。

然而很不巧的,目前大部分的需求,還是離不開10.4的環境,當要把在10.5開發的程式,轉到10.4的時候...
對於開發者來說,這可真是一個問候賈布斯全家大小的好時機...
首先是所有coredata中,使用property的部分,全部要換成key-value coding的方式去呼叫,光這點就足以讓你問候一下賈布斯高堂近況...
其次,data modal中如果有用到self inverse relationship時,你可能會想順便問一下賈布斯的祖母過得好不好...
再來,如果在NSTable中透過NSTableDatasource實作Drag and Drop,但卻是用binding取得table的資料的話...嗯...我想應該會有人想去研究一下賈布斯的祖譜吧...

2008年6月19日星期四

應用NSTabView切換視窗內容

在設計軟體時,有時候會需要在兩個不同的View之間做切換。
舉例來說,當我們在iTunes中,點擊左方資料庫的「音樂」,「影片」或「電視節目」,在右方的Detail View中,預設會以列表的方式呈現。
但當我們點擊到「Apple Store」時,則右方的Detail View會以類似網頁的方式,呈現目前Apple Store的內容。
在過去,剛開始學習Cocoa的時候,因為不清楚可用的元件,對於這類的需求,在實作上,往往會以一個Custom View做為Wrapper,用置換其Content View的方式,來達成切換內容的需求。
不過事實上,Cocoa已經提供了好用的元件--NSTabView,能夠更快速的完成類似的UI。
一般我們在使用NSTabView的時候,都是在需要明確的Tab元件 ,也就是需要有一個地方能夠秀出

  1. 目前的View的目的,或是名稱。
  2. 其他可選用的View。
不過上面我所舉的例子,則比較類似UI狀態的切換,通常不會秀出這些資訊--在這種情形下,一般我們不太會去考慮用到NSTabView。
但是,Cocoa的NSTabView,提供了另一種型態的使用法--Tabless TabView。利用NSTabView的Tabless type,就可以不用秀出Tab,看起來就如同用Custom View去實作View的切換一樣。
而使用Tabless type的View,還有一個好處,就是可以自行去更換Tab的樣式,而不需撰寫NSTabView的子類別。
Xcode的UI中,Project/Debug View的切換,就是一個實際應用的例子。

2008年6月12日星期四

關於「iPhone程式開發入門」一文,以及字首字根檔案

在過去一年來,一直有網友來信要求我所整理的字首字根檔案的權限。
而自iPhone SDK公布以來,也有些有興趣的朋友,留言或來信希望我能開放「iPhone程式開發入門」的權限。
在此表達一下個人在這個時點上,對這兩組文章的態度與作法。
首先,字首字根檔案的來源,是個人參加來欣方有毅老師的GRE課程的上課講義暨筆記的重新整理。
在目前的著作權法的架構下,公開此檔,可能會損害到方有毅老師的權益。
而個人目前也沒有意願,時間,精力,去與方老師商量開放的可能性。
網友如果想要此檔案,個人之前完成時,已寄送一份予方老師,你可以報名來欣的課程,我相信方老師應該會很願意分享給修課的學生。
至於「iPhone程式開發入門」一文,在目前(iPhone SDK beta7)的授權條款下,依然無法公開討論。
我本人,對iPhone SDK的授權條款,固然有諸多不滿,但基於個人之理念,在蘋果未正式宣告釋出之前,我不會再發佈相關文章。
以上,對於需要這些檔案的朋友,還請見諒。

2008年5月21日星期三

使用CoreData的小技巧

上個月在參加過CocoaHeades後,自己也試著使用CoreData。
雖然在現場藍兄講得清楚明白又容易,自個兒嘗試使用卻不是那麼回事。
果然是看人挑擔不吃力,自個兒挑擔壓斷肩...

在使用CoreData時,個人覺得比較麻煩的是,CoreData的說明文件似乎已預設開發者都對資料庫的設計有一定的基礎,所以並沒有提到一些基本的資料庫程式的原則-像是怎麼規劃,如何做正規化,Data Model的圖怎麼對應到實際的資料庫與呈現的介面之上? 除此之外,其他的地方照著文件一步步進行,也還算是輕鬆如意。

不過在使用Data Model設計完資料庫,並加以正規化後,在實作資料類別時,發生了一個小問題,在正規化的過程中,我設計了一個ID欄位,這個欄位的值在每一筆資料中都必需是獨一無二的。為了要讓這個值不重複,最簡單的作法是每增加一筆資料,就將這個值加1。在Apple的範例中,也是這麼做的:
程式碼:


- (void)awakeFromInsert
{
static int tempID = 1;
[super awakeFromInsert];
self.employeeID = [NSNumber numberWithInt:tempID++];

}

不過這樣的做法,在實際使用上會有些問題:
當我把現有的文件存檔後,關閉程式再載入時,此時新加入的資料,其ID又會從頭開始計算。顯然的,這種做法並不符合實際使用的需求。
因此,我在此手法上,稍微做了點擴充:
程式碼:

static int tempID = 1;
- (void)awakeFromInsert
{
[super awakeFromInsert];
self.employeeID = [NSNumber numberWithInt:tempID++];
}

- (void)awakeFromFetch
{
[super awakeFromFetch];
if([self.employeeID intValue] >= tempID)
tempID = [self.employeeID intValue]+1;

}


從初步的結果看來,這種做法是可行的,每當我讀取檔案時,awakeFromFetch會被喚起,並找到目前最大的ID值。之後在增加新的資料時,ID就會以目前資料庫的最大值為基礎,逐步增加。

除了上面的awakeFromInsert,暨awakeFromFetch外,我們還必須加上下面這段:
程式碼:

- (void)didTurnIntoFault
{
tempID = 0;
[super didTurnIntoFault];

}

不然的話,當我們關掉前一份資料庫,並產生一份新資料庫時,tempID會延用之前的最大值,而非重置為0。

這是目前我想到最簡單的做法,只是不知有沒有更適合的做法?

2008年4月21日星期一

iPhone程式開發入門

初稿...
iPhone程式開發入門
重新檢視一下,其實寫得蠻瑣碎的....
===================================
經人提醒,可能違反NDA,先暫時鎖上。
另將Objective-C基本語法部分抽出如下:
Objective-C基本語法

2008年3月14日星期五

Cocoa for Newbie

昨日CocoaHeads的投影片,順帶做一下Goggle Presentation的測試...



完整連結如下:Cocoa for Newbie

2008年3月11日星期二

寫給初學者的簡易程式設計概念

這篇文章,是為了讓初學者能大略了解傳統的(循序的)程式設計而寫的。
原本是要做為CocoaHeads的講稿的前言,但實在難以在有限的時間之內講述明白,因此寫成文章,在此先行釋出。
寫給初學者的簡易程式設計概念