Haskell串列是通過一連串對cons的呼叫來構建的,在解構語法后:
Prelude> (:) 1 $ (:) 2 $ (:) 3 []
[1,2, 3]
串列是由于它們是這樣的函式呼叫序列而導致的懶惰嗎? 如果這是真的,運行時如何在呼叫函式鏈的同時訪問這些值? 通過索引訪問是否也是一種語法糖? 我們如何用其他方式來表達它,而不是像這樣的糖?
Prelude> ( !) lst 1
2
這里的基本問題可能是:
串列是Haskell中的基本物體嗎,或者它們可以被表達為更多基本概念的組合?
是否有可能在最簡單的 lambda calculus 中表示串列?
我試圖實作一種語言,在這種語言中,串列被定義在標準庫中,而不是作為一個特殊的物體直接硬連接在決議器/解釋器/運行時中。
uj5u.com熱心網友回復: Haskell中的串列在語法上很特別,但從根本上來說并不特別。
從根本上講,Haskell的串列是這樣定義的: 只是另一個有兩個建構式的資料型別,這里沒有什么可看的,繼續吧。
上面是一個偽代碼,因為你實際上不能自己定義這樣的東西: 但是你可以定義一個等價的東西,比如: 而這在記憶體管理、懶惰等方面的作業完全相同,但它不會有漂亮的方括號語法(至少在Haskell 2010中是這樣;在現代GHC中,你也可以為自己的型別獲得特殊語法,這要感謝overloaded list )。
但是什么時候才會被評估?答案就在規范中:當有人試圖對一個值進行模式匹配時,該值就會被評估,而在那一刻,它被評估到被匹配的資料構造器為止。因此,對于串列來說,這將是當你去 data [] a = [] | (:) a ([] a)/span>
[]和(:)都不是一個有效的建構式名稱。對于內置的串列是一個特殊的例外。
data MyList a = Nil | Cons a (MyList a)
至于懶惰,這并不是串列的特殊之處,而是資料構造器的特殊之處,或者更準確地說,是資料構造器的模式匹配。在Haskell中,每個計算都是懶惰的。這意味著無論你構造了怎樣瘋狂的函式呼叫鏈,它都不會被立即評估。不管它是一個串列構造還是其他函式呼叫。沒有什么會被立即評估。case myList of { [] -> "foo"; x:xs -> "bar" } - 這時呼叫鏈被評估到第一個資料構造器,這是必要的,以便決定該構造器是 [] 還是 (:),這對于評估 case 運算式來說是必要的。
(!!)運算子的實作(查看源代碼)在串列中反復(遞回)匹配,直到它連續發現了N個(:)建構式,此時它停止匹配并回傳最后一個(:)建構式左邊的東西。
在 "最簡單的 "lambda微積分中,在沒有資料建構式或原始型別的情況下,我認為你唯一的選擇是對串列進行Church編碼(例如作為一個折疊,或者直接作為一個變形),或者從其他結構(例如對)中建立它們,這些結構本身就是Church編碼。蘭姆達微積分畢竟只有函式,沒有其他。除非你指的是更具體的東西。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/316942.html
標籤:
