What have you found for these years?

2011-05-07

display broken images in firefox

Otherwise, we won't know if there's a broken image in a web page.

A quick tip on enabling broken image placeholders in Firefox 3 and beyond

In short, put the following in:
Firefox/Profiles/[depends]/chrome/userContent.css

/*
 * Show image placeholders
 */
@-moz-document url-prefix(http), url-prefix(file) {
  img:-moz-broken{
    -moz-force-broken-image-icon:1;
    width:24px;
    height:24px;
  }
}

structural or sequential?

讓我覺得很困惑的東西在上一篇裡忘記講了。

在傳統的 imperative 程式裡,我們很自然會去想 flow, 會去想
程式是怎麼執行的。一行一行地執行,最簡單的說法大概是這樣。

而在 haskell 的程式裡,因為所有的東西都是 immutable, 再加上
所謂 lazy evaluation, call-by-need, whatever, 因此我們變得要
去描述問題,而非撰寫「步驟」去解決問題。也因此,我們無法
預測 runtime 上程式到底是怎麼執行的。到底是先算 A, 還是先算 B?

之前我還一直無法從這種「順序」的概念中逃離,所以對於 foldr
和 foldl, 我的理解一直變成 foldr 是從右邊開始,反之則從左邊開始。
這樣想很容易理解,因為我(們)寫程式太習慣「順序」了。在簡單的
例子中,大概也看不太出很大的差別。但如果試著用 IO 去觀察其真正的
執行順序的話,就會注意到這完全是無法解釋的。因為事實上,foldr
和 foldl 的結果是一種結構,而非一連串的順序。

foldr (-) 0 [1,2,3,4,5] 展開會是 1 - (2 - (3 - (4 - (5 - 0))))
foldl (-) 0 [1,2,3,4,5] 展開會是 ((((0 - 1) - 2) - 3) - 4) - 5

foldr 是向右結合,foldl 則是向左結合。cons list 也是一種向右結合的結構,
因此我們也會說,foldr 在 cons list 上,其實只是把 constructor 換掉而已。
我們不能把 fold 的結果看成一個數值,而應該是一種結構才對。一個很
簡單的例子,試著把 [1,2,3,4,5] 用 foldr 印出來看看:

foldr (curry (print . fst)) (return ()) [1..5]
updated 2011-05-14 22:44 或
foldr (const . print) (return ()) [1..5]
如果這樣寫不好懂的話,這是寫成 lambda 的樣子:
foldr (\i io -> print i) (return ()) [1..5]

如果我們試著去 evaluate 這個,也就是餵給 ghci 這個「結構」,
結果是我們只會得到一個 1, 而不是這個:
5
4
3
2
1

難道這樣應該說,foldr 其實是從左邊開始算才對嗎!?

回頭看剛剛的展開:1 - (2 - (3 - (4 - (5 - 0))))
用想像的,把裡面的 - 改成 curry (print . fst)
可以注意到,其實我們根本不在乎 print 後的結果 ( IO () ),
因此 evaluate 這個結構,就好像我們對一個 cons list 呼叫 head 一樣,
拿了第一個值,然後後面的根本就不需要,於是全部不會執行。

正確的寫法是這樣:
foldr (\i io -> io >> print i) (return ()) [1..5]
updated 2011-05-14 22:44 或
foldr (flip (>>) . print) (return ()) [1..5]

我們必須強迫算出 1 之前,必須先算出後面的東西。這整個展開來,就會變成...
return () >> print 5 >> print 4 >> print 3 >> print 2 >> print 1
monad law 告訴我們 bind 是 associative 的,所以這邊括號省略了。

而 foldl 的話則是:
foldl (\io i -> io >> print i) (return ()) [1..5]
updated 2011-05-14 22:44 或
foldl (flip (flip (>>) . print)) (return ()) [1..5]
展開來則是:
return () >> print 1 >> print 2 >> print 3 >> print 4 >> print 5
印出來就會是:
1
2
3
4
5

也就是說,唯一真正可以控制順序的,只有 IO monad 的 bind...

或是我們可以這麼說,我們總要有一個地方,可以說我們需要某個值?
不然程式要怎麼「開始」跑呢..? 或許可以這樣想像,haskell 的程式
就是一個巨大的 term, 所謂的執行程式,其實就是開始 reduce 的意思。
而這個神秘的開始 reduce, 大概就是 main 吧..


等等看 Josh 在 facebook 上說他要解釋 T-algebra,
說不定有助於理解 IO monad XDD 或是我真的該讀一讀這篇..
The Haskell Programmer's Guide to the IO Monad --- Don't Panic


其實這篇本來想說 strict or non-strict? 結果寫到這裡很累了,
乾脆就停在這,等下一篇再講...

denotational programming

updated: 2011-05-08 13:14 後來自己實驗發現 data/newtype
其實沒有 strictness 上的差別,Learn You a Haskell for Great Good!
這邊有點誤導...



IO monad 是黑魔法,pattern matching 有一半在詐欺...

這是最近在讀 Learn You a Haskell for Great Good!
Haskell: Not pure enough? 還有
Unraveling the mystery of the IO monad 等等,
加上過去的一些經驗後得到的暫時結論.....

簡單地說的話,就是 IO monad 跟其他 monad 根本完全不同?
很多地方嘗試教人 Haskell 會想從 IO monad 開始,畢竟連
Hello, World! 都不能跑,算什麼寫程式?可我真的認真覺得,
無論如何都不要先接觸 IO monad, 因為這真的是很詭異的東西...
用來用去得到的結論,都只覺得跟其他 monad 不太一樣。

至於 pattern matching, Learn You a Haskell for Great Good!
很明白地指出了,用在 data 上的 pattern matching 是 strict 的,
而用在 newtype 上的 pattern matching 則是 non-strict 的。
忽然間就讓解決了許多讓我困惑許久的疑問 --

updated: 2011-05-08 13:14 後來自己實驗發現 data/newtype
其實沒有 strictness 上的差別,Learn You a Haskell for Great Good!
這邊有點誤導...


為什麼明明應該要是 non-strict 的,卻變成是 strict 的?
為什麼可以「強迫」haskell 去計算某些東西?為什麼這些手法有效?
看來看去,好像都是歷史或是實作、現實考量,其實沒什麼特別的
道理在內?

為什麼 monad 是 applicative functor, 在 haskell 上卻沒有
特別這樣限制?該書說因為 monad 早在 applicative functor
之前就加入了 haskell, 因此沒有明確這樣的限制。

然後很多原本一直搞不懂到底要怎麼連起來的東西,終於有一點連起來的跡象。

不過嘛,就像 library 也統治著 programming language,
有一點跟現實接軌的地方,總永遠是第一步吧?只是覺得,
好像很少地方有在解釋這些一直讓我搞不懂的例外,以為
有另外一個更高層的東西,可以一口氣解釋這些東西....

* * *

標題的 denotational programming 來自:
Is Haskell a purely functional language?

或許這真的是個比較好的詞吧 XDD


p.s. 看什麼時候可以翻翻看這篇
The Haskell Programmer's Guide to the IO Monad --- Don't Panic
上次看 Abstract and Concrete Categories - The Joy of Cats
看到完全看不下去了,他的 concrete 對我來說還是太 abstract... XD
沒有實際的程式舉例,看不懂 :o

related post: 1938. 05-05 bottom, bottom, ⊥, ⊥, ⊥...

2011-05-06

Oracle v Google

Charles Nutter 非常深刻且誠懇的一篇

My Thoughts on Oracle v Google

實在長得有點誇張.... 看很久一直沒看完,中間又跳掉一大段 :o
之前的一點文摘在 buzz 上。

作者非常活躍,產出非常多,對很多東西都很有貢獻。

2011-05-05

rubygems 1.8.0

隨著 bundler 的發展,rubygems 也如火如荼在發展...
以前更新都不會有什麼問題,但在 1.3.7 之後,更新就常常
會造成一些奇怪的問題。

剛剛跑 rubygems_update 就很怪,會碰到詭異的錯誤。
然後發現自己的 ruby 好像也怪怪的,就乾脆砍掉重灌 :s

brew uninstall ruby
brew install ruby


重灌好之後,果然跑 gem up --system 就正常了,奇哉怪也。

接著跑 gem list 就能看到成千上萬的 deprecation warnings 呀呀呀
雖然他聲稱跑 gem pristine --all 可以修正現有的 gemspec,
但我跑過很多次(每次還跑很久...),問題一直沒有解決,還是狂噴
warnings, 太礙眼了。

還是自己寫 script (find + exec sed) 比較穩當...

find ~/.gem/ruby/1.9.1 -name '*.gemspec' -exec gsed -i -E 's/  s\.default_executable = %q\{.+\}//' '{}' ';'
接著看起來就正常了。另外,我之前老是碰到什麼 gemspec 裡的 date
變得很怪異,後面多了一堆 0 和 Z. 看起來是某個地方把 string 轉成
DateTime object, 於是重新轉成 string 時就加上了無意義的時間和
timezone.

看來看去還是不知道是哪個地方錯了,我 build gem 應該是走很標準的
流程才對。希望在 rubygems 1.8.0 裡不會再看到這怪錯誤了。
雖然說手動把時間改對也只是舉手之勞,可還真擔心別人用我的 gem
也會碰到同樣的問題 :s

bottom, bottom, ⊥, ⊥, ⊥...

日前看到這一篇: The Point of Laziness

劈頭就說:

It is not possible in Haskell to define the type of natural numbers, nor
the type of lists of natural numbers (or lists of anything else), nor any
other inductive type!

讓我感到很困惑,最近滿腦子都在想這些事。到現在也還沒什麼肯定的想法,
但我相信如果繼續拖下去,繼續想繼續看的話,大概永遠沒辦法筆記吧 XD

所以就暫時把目前想到的一些東西寫下來。一開始這篇我真的看不太懂,
只覺得他講了很多結論,卻看不到過程。逼不得已,只好連 comment
也一篇篇看。[0]

後來讀到其中一個 comment gasche 提到

Robert Harper is here referring to the *lifting* behavior of Haskell
data types, where you may have exotic values using ⊥ when you
make for a sum. For example, type `Either a b` has all elements of a,
all elements of b, plus a ⊥ element. So this is not exactly a disjoint
sum (for a precise definition of what he means by “sum”, see the
categorical definitions of sum and product).

雖然我不知道 categorical definitions 是什麼,是指在 category theory
上的定義嗎... 如果是的話,我懷疑我是否能搞懂。總之作者 (Rober Harper) 回答:

More precisely, all types in Haskell are pointed (not necessarily
lifted). But, yes.

接著 Andreas Rossberg 又補充:

To expand on Bob’s reply: his point (and what he complains about in
his post) is that this type in fact does not represent the natural
numbers in a lazy language, because the type is unavoidably
inhabited by additional “values”. For example,
nonnat :: Nat
nonnat = Succ nonnat
Despite the type, this is not a natural number, and inductive principle
don’t apply. Strict semantics, like in ML, precludes such examples.

我不怎麼想再繼續引用下去了,因為後面還有不少。但每一篇都揭發出一些
新的東西,所以還是繼續看下去比較好... Kenneth B 說:

A lot of commenters here seem to think that the definition
data Nat = Zero | Succ !Nat
disallows “nonstandard” inhabitants, but this is obviously false.
The “strictness” annotation in !Nat just requires that the
argument to Succ be in head normal form, not
be fully evaluated. Thus, you can easily define:
loop :: Nat
loop = Succ loop
without running afoul of the “strictness” annotation. Indeed,
you can also define:
bad :: Nat
bad = Succ (Succ undefined)
and GHC will not complain about the inner Succ being applied
to undefined.

看到這裡,好似理解了什麼是 natural number 不是 natural number,
但又不怎麼明白這跟 strictness 有什麼關係。ML 應該也可以寫出這種
程式,應該也不會是 compile time 抓得到的問題?畢竟這好似 termination
check, 要 type checker 檢查這件事,則會陷入 halting problem;
然而如果強迫程式一定要 terminate, 那就不會是 Turing complete,
而且現在想到 Agda 還是會怕 XDD

will87 倒是說出了我的疑問,雖然 Rober Harper 說那是錯的:

In Haskell the strict definition of Nat means that fix Succ
(omega/infinity) is intensionally equal to _|_ (which ML types
do contain as it is a Turing Complete language, i.e. you can
write non-terminating definitions). The values which can inhabit
this type are therefore equivalent to the least fixed point of
its definition and hence are the inductive naturals, and
equivalent to the ML type.

這麼多人問了這麼多次,他總算解釋了更多:

In a lazy language non-termination is a value, whereas in an eager
language it is an effect. In particular, variables in a lazy language
range over computations, including the non-terminating computation,
whereas in a strict language they range only over values. Given a
variable x of type nat, if natural number induction were valid, you
could prove that x is either zero or a successor. This is true for ML,
but false for Haskell, because x could be “bottom”, ie the
non-terminating computation, which is a value. For this reason no
inductive type, not even the Booleans, are definable in Haskell. It is
not a matter of strictness annotations on data declarations, it is a
matter of the most fundamental level of semantics of the entire
language itself.

Umm... 也就是說,在 Haskell 中 const True undefined 我們還是會
得到 True, 就算得到了這個 term, 也不代表裡面的 Nat (undefined)
真的是一個 Nat, 或其實是 ⊥ ? 而在 ML 中,反正 const True undefined
就是 ⊥ 了,所以也不用去考慮 Nat 到底是不是 ⊥ ?

如果是這樣的話,那或許確實可以理解為什麼會想要 strict 而非 non-strict,
畢竟對於程式性質而言,non-strict 有太多可能性,似乎確實變得難以證明
許多?這一點,也可以在 Inside P4 一系列的文章中,看到考慮各種 ⊥,
真的讓情況變得很複雜。

Hussling Haskell types into Hasse diagrams

這篇我大抵上看完了,大概就是在 FLOLAC 08 10 上聽到的 domain theory
那些東西... poset, Hasse diagram, etc, etc. 大抵上我猜是有懂啦 :s
不過最後那段倒是確定不太懂:

We almost recover Nat if we set a to be (), but they’re not quite
isomorphic: every () might actually be a bottom, so while [()] and [⊥]
are equivalent to one, they are different. In fact, we actually want to
set a to the empty type. Then we would write 5 as [⊥, ⊥, ⊥, ⊥, ⊥].

啊啊啊,寫到這裡,重新讀幾次,卻發現自己好像懂了。這邊應該是在說,
如果我們讓 List a 的 a 是 Unit 的話,就可以讓 List Unit 跟 Nat 是
isomorphic 的,也就是說,5 事實上就是 [(), (), (), (), ()], 也就是
Succ (Succ (Succ (Succ (Succ Zero)))). 但事實上,因為 non-strict 的
關係,Unit 的 value 其實不只是 (), 也可能是 ⊥. 因此我們真正希望跟 Nat
是 isomorphic 的是 List Empty 而非 List Unit 了...

看來我可以安心繼續看 Gin and monotonic 了。除此之外,
還有另一篇 How I Learned to Stop Worrying and Love the ⊥

[0] 講個題外話,comment 裡有一個人,誤把作者當成初學者,不禁
開始讓我想,是什麼情況下,會導致這種錯誤的結論。大概要嘛是沒有
RTFA, 要嘛是像我一樣完全不懂他在說什麼,要嘛就是沒有連其他文章
也順便一起讀讀吧...

不過這或許也證明一件事,東西寫得太刺激,總是會吸引到一些搞不清楚
狀況的人吧?或是說,寫得隱晦一點,例如不講結論,這樣搞不清楚狀況
的人就不會搞錯狀況,就只停留在搞不清楚的階段...

*

這真的是個很漫長的路!太多太多東西現在想起來好像很單純,可是我真的
是花了很多很多時間,才慢慢對這些東西有所體會。搞到最後,真的會不知道
到底什麼東西是讓自己搞懂的關鍵,每一點自己看到的東西,自己體會到的
東西,都是拼圖的一小片。能快速理解,也只是因為過去知道或是看過類似的
東西,因此可以從半路開始爬,或是從岔路走過來,而非從頭開始走。

也就是說,其實自己也不見得真的那麼笨啦,只是浸淫的時間不夠吧...

今天聽穆老師講的東西,自己是都早已聽到爛了,不過多聽幾次好像又多有
所會。而聽自己已經懂的東西,則能有餘裕邊聽邊思索,如果要跟人解釋,
用什麼樣的解釋,用什麼樣的類比,用什麼樣的象徵來表達會比較容易懂。
多想這些其實也有助於理解和想像。

還有與 jaiyalas 聊天的過程中,點醒了我... 什麼東西忘記了 Orz
也太快就變成拼圖中的一片了吧 :s 但說真的,討論這些倒也有點像是
pair programming清談... 有時候自己會有莫名其妙的盲點,這時候
就需要旁人來戳破。


p.s. Existential Type 裡很多文章都讓我陷入思索,
Inside P4 裡的文章都寫得很清楚,還附有趣的圖解。

另外會想到的則是 Learn You a Haskell for Great Good!
雖然風格不同,但有時候我不知不覺會把他們連在一起。
這本書我覺得讀起來相當愉悅,不過這以後再說吧,值得
特別拿來說。


p.s.2 我好想學插圖風啊 XDD 有閒的話試試看弄個 simple and clean 的風格吧!

2011-05-02

[ANN] CuBeat alpha release

I'm happy to announce that we have released the second
public alpha version of CuBeat, which can be found on
Google Code downloads page. Currently, we have 4 releases,
Windows 32 bit, Mac OS X 64 bit, and Linux 32/64 bit.

If you're interested about the source, it is hosted
on Github, licensed under Apache License 2.0.

Other information can be found in the distribution.

Feel free to contact the development team via devblog,
or contact me directly by anyway if you have any question,
thanks!

* * *

我很榮幸在此宣佈,我們釋出了 CuBeat 的第二個公開測試版,
大家可以在 Google Code 的下載頁面上找到。目前我們有四個
版本可以下載,分別是 Windows 32 bit, Mac OS X 64 bit,
和 Linux 32/64 bit.

如果對原始檔(源碼)有興趣的話,目前放在 Github 上,
以 Apache License 2.0 釋出。

其他資訊可以在下載下來的檔案中找到。

如果有任何問題,可以至開發部落格留言,或是用任何方法聯繫我,
謝謝!

2011-05-01

無比疲憊

本來想說週末要來處理 ripl, ripl-multi_line, 和 rest-graph 的事。
結果到現在一件也沒辦法做,昨天又弄到好晚,覺得整個人要攤了,
今天想到還有一堆事要做,就怎麼樣也提不起精神。

也不知道是因為這樣,還是其實沒什麼關係,自己又沉浸在剛剛
夢裡的氣氛。剛爬起來時百感交集,結果一被打斷,現在則是一片
空白。然後我發現自己好像只想沉浸在夢裡似的,因此對於被打斷
而造成腦裡一片空白感到有點著惱。

很多事情變了,也很多事情沒變,也很多事情變了又變了,
結果最後回到當初那個樣子。

All texts are licensed under CC Attribution 3.0