caasih.net

Build Your Own Haskell Compiler #1

跟著 BYOHC 做自己的 compiler ,也兩個月了。

目前 CAlexLu 做到 transpiler 。還跟不上。

為了觀察每一步是怎麼 reduce ,近一個月前全部重做,從 LiveScript 移到 ES2015 上。 interpreter 倚賴 Promise 完成 async 操作,於是 internal functions 可以傳回 Promise 好處理 I/O 。

略讀了 The Implementation of Functional Programming Languages , 1987 年流行的作法還是 [Response] -> [Request] ,而不是 I/O monad 。前幾天才找到 SPJ 的 Tackling the awkward squad,想搞清楚 IO 到底在做什麼。

文中提到 IO 很像 state monad (但不是...),還不明白 GHC 是怎麼做的,只好真的用 state monad 做看看:

bind :: IO a -> (a -> IO b) -> IO b
bind = \IOa \f IOa \a \RealWorld pair (f a) RealWorld

於是可以把在 IO a 中的 RealWorld 傳到 IO b ,正如 #haskell.tw 上大家形容的那樣:「把 RealWorld 傳下去」。

問題出在中間的 a -> IO b 裡面用到的 return,把 b 變成 IO b 的是它,於是它需要知道 IO a 中的 RealWorld 是什麼東西(當然要是我可以把 RealWorld 變不見,又能留下它造成的效果最好,可是我還不懂該怎麼做)。

untyped lambda calculus 中沒有 type class 可用,我又不是用 env 實作 interpreter ,最好只好把 bind 的 type 改成:

bind :: IO a -> ((b -> IO b) -> a -> IO b) -> IO b

那個 b -> IO b 就是 return 。(讓我想起 Angular.js 的 dependency injection )

How to desugar Haskell code 說 type class 在 desugar 後會直接呼叫對的 function ,應該不用像我這樣亂改 type 。

接下來沒有 haskell-src-exts 跟 haskell-src 可以用,該怎麼做才好?


這次學到兩件事,一是傻傻找 left-most out-most 的效能有多慘,現在 playground 沒有 delay ,每步都用 requestAnimationFrame ,也要好久才能把讀進去的字串吐出來。難怪那麼多論文都在講,怎麼有效率地 reduce 。二是對 pure functional language 來說,時間順序不重要,只有在和困在時間中的人類互動時,才需要考慮這點。

欸,中二病又發了,快去睡覺比較實在。

Isaac Huang 發佈於