Swift,Haskell這種可以自定義運算符的語言(不僅僅是重載),在實現編譯器時跟其他語言又什麼區別嗎?


Swift不清楚。。

Haskell里運算符重載實際上就是type class的意思,用戶自定義類型如果是某個class的instance,實現了這個class的函數,那麼在所有需要用到這個class下類型的地方,都可以使用這個自定義類型了。比如自定義類型是Show的instance,實現了show函數,就可以print,是Eq的instance,實現了(==),就可以比較等於/不等於,是Ord的instance,實現了compare,就可以比較大小關係。

編譯器實現type class的方法(假設通過了類型檢查),有static monomorphization,intentional type analysis和dictionary passing等方法。

dictionary passing舉個例子,對於一個類型簽名為Show a =&> a -&> ...的函數,替換成一個(a -&> [Char]) -&> a -&> ...的函數,這裡額外多傳進去的這個(a -&> [Char])的東西就是show函數的實現;對於更複雜的、有多個函數的class,就改成先傳一個包含相應函數實現的dictionary進去。這種方法跟C++里對象的成員函數隱式地多傳一個this指針有異曲同工之妙。

static monomorphization是將所有用到Show a =&> a -&> ...的函數的地方全部靜態改寫成a -&> ...,針對不同的show生成不同版本的函數,類似於C++的template instantiation。。intentional type analysis就直接是運行時判斷類型,然後dispatch到相應的show函數。

一般而言運行時判斷的方法會犧牲一些性能,但是方便支持seperate compilation等特性;編譯期展開的方法生成代碼性能更好,但不能實現separate compilation(想想C++里那些header-only的模板庫),對類型系統有更多限制。


需要一定的語法處理機制:優先順序、結合性、單雙零目共存(如減號和負號)、隱含操作符(隱含乘、連接)……;

需要對語義做好設計:短路、調用約定、元(quote、代碼自修改)……;

需要規劃代碼間交互:分離編譯的extern名、作用域和引入導出……。

差不多這些,自定義運算符就可以玩得很爽了。


推薦閱讀:

新版本編譯器是用自己(新版本編譯器)重新編譯後發布還是用舊版本編譯器編譯發布?
用new申請的內存如果使用free函數來釋放會有怎樣的結果?
如何看待 NOIP 競賽選手用機與評測機編譯器行為不一致而導致評測出現的問題?
為什麼微軟不單獨發行編譯器和鏈接器?
如何看待微軟研究院的LEAN項目沒有使用微軟出品的編譯器?

TAG:編程 | Haskell | 編譯原理 | 編譯器 | 詞法分析 |