我的雲端生活網 - Life+
Thursday, June 25, 2009
Monday, June 15, 2009
imoo msn機器人測試平台公告
為了提供更即時的測試諮詢服務,imoo msn機器人測試平台,將於下週三(2009.6.24)取消所有未經申請試用的認證資訊,改由申請制的方式辦理測試,相關測試申請可直接發信至service@imoo.tw 洽詢
Thursday, June 11, 2009
(翻譯) Erlang 程式設計第七章:並行風格
Joe Armstrong 在 Erlang Programming 書中有一段提到「平行程式設計」 (Concurrent-oriented programming, COP) 的概念。以下翻譯那一段文章,提供許多人即使在用非平行程式設計方式開發平行系統架構時,也可以引用這些概念。
並行風格
人都知道何謂並行 對並行的深入認知,直接連通到我們腦內。我們能極速地對刺激做反射動作,是用到腦的一部份,稱為杏仁體。若少了這樣的反應,我們可能會死。有意識的思考動作太慢。而用到思考「快拉煞車桿」耗掉的時間,我們早就做了那個動作了。
行駛在幹道上的時候,我們心裡會打量十幾輛或百來輛車。這不經過意識思考。如果我們沒本事做到這種事,可能就會死。
世界是平行的 假如我們要寫一些程式,表現如同在真正世界中表現著的其他物件,這些程式會有個並行的組織方式。這是何以我們該用「並行程式語言」來寫程式。
然而我們很常用「循序程式語言」寫真實世界的程式。真是多餘的難。
用我們設計來寫並行應用程式的語言吧!並行程式開發會變得超容易。
Erlang 程式建構我們思考及感興趣的模型 我們不共用記憶。我有我的記憶,你有你的記憶。咱們是兩個腦袋,一人一個。兩個腦袋不會融合成一個。要改變你的記憶,我要對你送訊息,或者說,我要揮揮手。你聽到了,或瞧見了,你的記憶就會改變。不過,如果沒問你問題並看看你的反應,我不知道你有沒有收到我的訊息。
這是有 Erlang 程序的情況該是的樣子。 Erlang 程序沒有共用記憶體,每個程序有自己的記憶體。要改變其他程序的記憶體,你必須送個訊息,期望對方收到並了解訊息。要確定別的程序已經收到你的訊息,並且改變他的記憶體了,你必須問問他 (也送個訊息) 。這完全是我們都怎麼互動的模式。
煦:嗨,比爾,我的電話號碼是 45-67-89-12 。
煦:你聽到了嗎?
比爾:有,你的號碼是 45-67-89-12 。
這些互動模式是我們如此熟悉,從小到大我們都和這世界這樣互動,觀察它,對它送送訊息,然後看看反應。
人們發揮功用,如獨立個體般送訊息做溝通 這是 Erlang 程式做事的辦法,也是人們做事的辦法。所以,很容易學懂一份 Erlang 程式。
一份 Erlang 程式用許多成千或上百千的小程序構成。這些小程序獨立運作。它們彼此送訊息溝通。每個程序有自己的記憶體。它們表現得像一大房間的人群彼此在饒舌交談。
這讓 Erlang 天生就是簡單,容易維護並擴充。假定我們有十個人 (或程序) ,他們要做太多工作。可以怎麼做呢?找更多人來。而我們怎麼管理這些人呢?很簡單,就對他們喊口令 (或叫廣播) 。
Erlang 程序沒有共用記憶體,所以記憶體使用時不需要鎖定。有鎖的地方就有會有鑰匙,而有鑰匙就可能會遺失鑰匙。當你鑰匙掉了會怎麼樣呢?你會驚慌得不知道怎麼辦。在軟體發生的,則是當你丟掉了鑰匙,鎖定就造成錯誤。分散式軟體系統如果有鑰匙和鎖,都會出錯。
而 Erlang 可沒有鎖和鑰匙。
有人死掉,其他人一定會注意到 假如我在一個房間裏突然傾覆而死,有人可能會注意到。 Erlang 程序就像人們,他們有時可能死掉。但不像人們的是,人們死掉會用盡力氣叫出聲,而叫聲與他們的死因有關。
想想滿滿一整房間的人,有人突然倒斃了。像他們死的時候,會叫說「我的心臟──我要死了」或是「我的胃抽搐」。這就是 Erlang 程序所做的。一條程序可能死前說:「我死於除以零。」另一條程序可能說:「我死於向空串列要最後一項串列資料。」
現在在我們滿是人的房間裏,假想有位特定的仁兄,他的任務是清除遺體。假定有珍和尚二人,如果珍死掉,尚會修正對珍的死亡所有的錯誤。如果尚死亡,珍會修定那些錯誤。珍和尚是被無形的契約連成一體,約定若有一方死亡,另一方會修正所有造成其死亡的錯誤。
這就是 Erlang 怎麼處理錯誤偵測的方法。程序可以連成一體。如果一條程序死掉,另一條程序獲得一則錯誤訊息,指出前一條程序為什麼死掉。
基本是這樣。 Erlang 怎麼做事如以上所述。
現在我們學到的東西有:
下一章我們開始寫並行程式。我們需要學三種基本項: spawn 、 send (這用到 ! 運算子) 和 receive 。然後寫一點簡單的並行程式。
當程序死掉的時候,如果有其他程序跟它連成一體,其他程序就會注意到。這是第九章的主題,「並行程式的錯誤」。
在你讀下兩章的時候,想著房間裏有一群人。人們是程序。在房間裏的人們有自己私有記憶,這記憶就是程序的狀態。要改變你的記憶,我就跟你講話,而你就聽,這是送訊息和收訊息。我們會有兒女,這是 spawn (生產) 。我們死掉,就是一條程序結束了。
並行風格
人都知道何謂並行 對並行的深入認知,直接連通到我們腦內。我們能極速地對刺激做反射動作,是用到腦的一部份,稱為杏仁體。若少了這樣的反應,我們可能會死。有意識的思考動作太慢。而用到思考「快拉煞車桿」耗掉的時間,我們早就做了那個動作了。
行駛在幹道上的時候,我們心裡會打量十幾輛或百來輛車。這不經過意識思考。如果我們沒本事做到這種事,可能就會死。
世界是平行的 假如我們要寫一些程式,表現如同在真正世界中表現著的其他物件,這些程式會有個並行的組織方式。這是何以我們該用「並行程式語言」來寫程式。
然而我們很常用「循序程式語言」寫真實世界的程式。真是多餘的難。
用我們設計來寫並行應用程式的語言吧!並行程式開發會變得超容易。
Erlang 程式建構我們思考及感興趣的模型 我們不共用記憶。我有我的記憶,你有你的記憶。咱們是兩個腦袋,一人一個。兩個腦袋不會融合成一個。要改變你的記憶,我要對你送訊息,或者說,我要揮揮手。你聽到了,或瞧見了,你的記憶就會改變。不過,如果沒問你問題並看看你的反應,我不知道你有沒有收到我的訊息。
這是有 Erlang 程序的情況該是的樣子。 Erlang 程序沒有共用記憶體,每個程序有自己的記憶體。要改變其他程序的記憶體,你必須送個訊息,期望對方收到並了解訊息。要確定別的程序已經收到你的訊息,並且改變他的記憶體了,你必須問問他 (也送個訊息) 。這完全是我們都怎麼互動的模式。
煦:嗨,比爾,我的電話號碼是 45-67-89-12 。
煦:你聽到了嗎?
比爾:有,你的號碼是 45-67-89-12 。
這些互動模式是我們如此熟悉,從小到大我們都和這世界這樣互動,觀察它,對它送送訊息,然後看看反應。
人們發揮功用,如獨立個體般送訊息做溝通 這是 Erlang 程式做事的辦法,也是人們做事的辦法。所以,很容易學懂一份 Erlang 程式。
一份 Erlang 程式用許多成千或上百千的小程序構成。這些小程序獨立運作。它們彼此送訊息溝通。每個程序有自己的記憶體。它們表現得像一大房間的人群彼此在饒舌交談。
這讓 Erlang 天生就是簡單,容易維護並擴充。假定我們有十個人 (或程序) ,他們要做太多工作。可以怎麼做呢?找更多人來。而我們怎麼管理這些人呢?很簡單,就對他們喊口令 (或叫廣播) 。
Erlang 程序沒有共用記憶體,所以記憶體使用時不需要鎖定。有鎖的地方就有會有鑰匙,而有鑰匙就可能會遺失鑰匙。當你鑰匙掉了會怎麼樣呢?你會驚慌得不知道怎麼辦。在軟體發生的,則是當你丟掉了鑰匙,鎖定就造成錯誤。分散式軟體系統如果有鑰匙和鎖,都會出錯。
而 Erlang 可沒有鎖和鑰匙。
有人死掉,其他人一定會注意到 假如我在一個房間裏突然傾覆而死,有人可能會注意到。 Erlang 程序就像人們,他們有時可能死掉。但不像人們的是,人們死掉會用盡力氣叫出聲,而叫聲與他們的死因有關。
想想滿滿一整房間的人,有人突然倒斃了。像他們死的時候,會叫說「我的心臟──我要死了」或是「我的胃抽搐」。這就是 Erlang 程序所做的。一條程序可能死前說:「我死於除以零。」另一條程序可能說:「我死於向空串列要最後一項串列資料。」
現在在我們滿是人的房間裏,假想有位特定的仁兄,他的任務是清除遺體。假定有珍和尚二人,如果珍死掉,尚會修正對珍的死亡所有的錯誤。如果尚死亡,珍會修定那些錯誤。珍和尚是被無形的契約連成一體,約定若有一方死亡,另一方會修正所有造成其死亡的錯誤。
這就是 Erlang 怎麼處理錯誤偵測的方法。程序可以連成一體。如果一條程序死掉,另一條程序獲得一則錯誤訊息,指出前一條程序為什麼死掉。
基本是這樣。 Erlang 怎麼做事如以上所述。
現在我們學到的東西有:
- Erlang 程式由一大堆程序構成。這些程序可以彼此送訊息。
- 這些程序可能會接收訊息並瞭解訊息,也可能不會。如果你要知道訊息有沒有收到並解讀,你必須向程序送訊息,並等它回應。
- 成對的程序可以被連成一體。如果其中之一死掉,錯誤訊息會送給另一個程序,訊息中包含前一程序為什麼死掉的理由。
下一章我們開始寫並行程式。我們需要學三種基本項: spawn 、 send (這用到 ! 運算子) 和 receive 。然後寫一點簡單的並行程式。
當程序死掉的時候,如果有其他程序跟它連成一體,其他程序就會注意到。這是第九章的主題,「並行程式的錯誤」。
在你讀下兩章的時候,想著房間裏有一群人。人們是程序。在房間裏的人們有自己私有記憶,這記憶就是程序的狀態。要改變你的記憶,我就跟你講話,而你就聽,這是送訊息和收訊息。我們會有兒女,這是 spawn (生產) 。我們死掉,就是一條程序結束了。
Wednesday, June 10, 2009
ithome blog 與微軟bing搜尋 不合
使用bing 查詢 關鍵字msn機器人時,會出現這些訊息
This page looks plain and unstyled because you're using a non-standard compliant browser. To see it in its best form, please visit upgrade to a browser that supports web standards. It's free and painless.
- blog.ithome.com.tw/index.php?blogId=1302
- · 庫存頁面
Wednesday, June 3, 2009
imoo msn機器人 行銷服務
imoo 提供2種創新的行銷服務模式
請問有範例可以參考嗎?
imoo msn 機器人應用概念圖 |
Monday, June 1, 2009
排列函數
排列和組合是很容易處理的問題。但不知道為什麼,在資訊科系學寫程式之後,排列卻變成相當難的問題。難的地方是在像 C 語言的程式步驟和資料型態上,要考慮很多額外的東西,也遇到很多小麻煩。因此,「取一列資料的全部排列情況」變成一項我一直不會寫程式解決的問題。
解析
而使用像 Haskell 這樣的函數程式語言,將過去所學的知識加以翻覆、折疊,重新整理出一條順暢的思考路線。我最近寫出的排列函數如下;再下去,讓我解釋一下函數構成的想法。
allPermu :: (Eq a) => [a] -> [[a]]
allPermu xs = compact rs
where rs = map (map (\x -> xs!!x)) (allPermu' [0..((length xs)-1)])
allPermu' :: (Eq a) => [a] -> [[a]]
allPermu' [] = [[]]
allPermu' xs = concat (map f xs)
where f = \x -> map (x:) (allPermu' (filter (x/=) xs))
compact :: (Eq a) => [a] -> [a]
compact [] = []
compact (x:xs) = if any (x==) xs then compact xs
else x : compact xs
解析
1. allPermu' 函數:取一列資料的全部排列情況
首先,我覺得取一列資料,如 [4, 3, 4, 5] 的全部排列情況,就是先考慮 4, 3, 4, 5 各數字,將原列資料的這個數字拿掉,求剩下的一列資料的全部排列情況,然後將這個數字都擺在全部排列情況的每一項前面。就這個例子來說, 4, 3, 4, 5 分別要做一次這樣的動作。只考慮 3 , 3 要和剩下的 [4, 4, 5] 的全部排列組成。 [4, 4, 5] 的全部排列有 [4, 4, 5], [4, 5, 4], [5, 4, 4] ,讓 3 擺在每一項的前面就產生 [3, 4, 4, 5], [3, 4, 5, 4], [3, 5, 4, 4] 這些。
首先,我覺得取一列資料,如 [4, 3, 4, 5] 的全部排列情況,就是先考慮 4, 3, 4, 5 各數字,將原列資料的這個數字拿掉,求剩下的一列資料的全部排列情況,然後將這個數字都擺在全部排列情況的每一項前面。就這個例子來說, 4, 3, 4, 5 分別要做一次這樣的動作。只考慮 3 , 3 要和剩下的 [4, 4, 5] 的全部排列組成。 [4, 4, 5] 的全部排列有 [4, 4, 5], [4, 5, 4], [5, 4, 4] ,讓 3 擺在每一項的前面就產生 [3, 4, 4, 5], [3, 4, 5, 4], [3, 5, 4, 4] 這些。
我先要有一個函數是 f = \x -> map (x:) (allPermu' (filter (x/=) [4, 3, 4, 5]) ,是一個函數名為 f ,接到一個參數叫 x ,就把 [4, 3, 4, 5] 中不等於 x 值的項目取出成一列,用一個取全部排列的函數名叫 allPermu' 求少了 x 的全部排列情況。 (只是 allPermu' 在此還沒講它怎麼寫。) 然後,用 map 函數將 (x:) 套到少了 x 的全部排列的每一項前面。這種想法很簡單,對一列資料的每一項,都先把少了那一項的其他資料做排列,所得到的全部排列情況再把少掉的那一項套在前面。
於是,可以說 allPermu' [1, 2] = map f [1, 2] ,再解開就是
map f [1, 2] = [f 1, f 2] = [map (1:) (allPermu' (filter (1/=) [1, 2])),
map (2:) (allPermu' (filter (2/=) [1, 2]))]
filter (1/=) [1, 2] = [2]
filter (2/=) [1, 2] = [1]
allPermu' (filter (1/=) [1,2]) = allPermu' [2] --這裡細節省略,我們知道 [2] 全部排列就是 [[2]]
allPermu' (filter (2/=) [1,2]) = allPermu' [1] = [[1]]
map f [1, 2] = [ map (1:) [[2]] , map (2:) [[1]] ]
= [ [[1, 2]] , [[2, 1]]]
最候出現答案了,但是資料結構的深度加一層。如果把 allPermu' 函數寫成以下這樣......
allPermu' xs = map f xs
where f = \x -> map (x:) (allPermu' (filter (x/=) xs))
這是有麻煩的程式。因為當 allPermu' 處理 xs 一次,展開成右邊算式 map f xs 得到的答案會讓資料結構加一層。本來對 [1, 2] 我們想求的答案是 [[1, 2], [2, 1]] ,但是按照前面的計算結果,答案卻是 [[[1, 2]], [[2, 1]]] 。雖然算得出答案,但是表達一列資料的層次越來越深。這時我們需要一個函數讓 [[[1, 2]], [[2, 1]]] 變成 [[1, 2], [2, 1]] ,把資料結構層次降低一層。有一個預設的函數叫 concat 可以做這件事情,如果有一列資料是 [a, b, c, ...] 而 a, b, c, ... 是另外幾列資料, concat [a, b, c, ...] 是把 a, b, c, ... 這幾列資料銜接在一起,於是資料結構的層次減低一層。所以,使用 concat 把 allPermu' 寫得好的程式如下:
allPermu' xs = concat (map f xs)
where f = \x -> map (x:) (allPermu' (filter (x/=) xs))
上面這個 allPermu' 是遞迴的情況。而遞迴程式應該要包含遞迴部份和基底部份。把基底和 allPermu' 函數的型態加進去,完整的 allPermu' 函數就是:
allPermu' :: (Eq a) => [a] -> [[a]]
allPermu' [] = [[]]
allPermu' xs = concat (map f xs)
where f = \x -> map (x:) (allPermu' (filter (x/=) xs))
然而, allPermu' 有個問題是,如果處理的資料列中有重覆資料,因為 filter (x/=) xs 比對 x 值是否相同的作用,會讓 allPermu' [4, 4, 5] 求出不對的答案。即使如此,至少 allPermu' 函數處理一列每個項目都彼此不同的資料是做得對的。後來我想,任何一列可能有重複項目的資料背後都藏了另一列項目彼此不同的資料,就是由原列每一個項目存在的位置編號。例如, [4, 4, 5] 對應到它們的位置編號 [0, 1, 2] 。以下的 allPermu 函數,在處理任何一列資料時,先取出該列資料的一列位置編號,用 allPermu' 函數產生位置編號的全部排列,再將這些排列轉換為原資料。
2. allPermu 函數:產生任何一列資料的全部排列情況
在 Haskell 寫 [0..9] 可以得到 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] ,是取得等差遞增序列的特殊語法。對任何一列資料,例如 [4, 3, 4, 5] ,可以寫 [ 0 .. ((length [4, 3, 4, 5]) - 1) ] 產生從 0 開始的遞增序列,也就是 [4, 3, 4, 5] 的位置編號 [0, 1, 2, 3] 。
於是, allPermu' [0..((length [1, 2])-1)] 是 [1, 2] 位置編號的全部排列情況, [[0, 1], [1, 0]] 。接著要將 [[0, 1], [1, 0]] 轉換成 [[1, 2], [2, 1]] 。用 map (\x -> [1,2]!!x) [0, 1] 可以做到這件事情。給一個數字 x , [1, 2] !! x 就是在 [1, 2] 列中取第 x 個位置的項目。所以,以下的程式可以將 [[0, 1], [1, 0]] 轉換成 [[1, 2], [2, 1]] :
map (map (\x -> [1, 2]!!x)) [[0, 1], [1, 0]]
第一個 map 將第二個 map 伴隨其參數的段落,即 map (\x -> [1, 2]!!x) ,套到 [[0, 1], [1, 0]] 的每一個項目。接著對 map (\x -> [1, 2]!!x) [0, 1] 來說,是將函數 \x -> [1, 2]!!x 套到 [0, 1] 的每一個項目。所以基本上, allPermu 函數可以寫成:
allPermu xs = rs
where rs = map (map (\x -> xs!!x)) (allPermu' [0..((length xs)-1)])
但是,考慮 allPermu [4, 3, 4, 5] 會發現出現一些重複的項目,例如,雖然 [0, 1, 2, 3] 和 [2, 1, 0, 3] 的確是兩種不同的排列情況,卻都轉換成 [4, 3, 4, 5] 。於是第三個函數 compact 是將多個重複項目刪掉。 compact 函數在 Haskell 是很普遍的程式處理方式,在此省略其介紹。
3. 結論
本篇由一件以 Haskell 撰寫的全部排列函數,解析一般的處理排列問題的遞迴解題方式。求一列資料的全部排列,是對資料列中的每一項,先求其他項目的全部排列,再將這一項分配結合到其他項目全部排列的每一項之前。透過函數程式語言的寫作方式,可以讓我們重新抓到人們解決問題的直覺能力,使我們從以往局限在程式執行步驟數量的思考方式中得到解脫。
Subscribe to:
Posts (Atom)