來自 Python 和 Javascript 背景,我真的不明白為什么在 Haskell 中更新串列元素并不簡單。我的意思是,為什么我不能寫一些像這樣簡單的東西myList[0] = "newValue"?
所以,我有兩個問題:
- 為什么在 Haskell 中更新串列元素不是很簡單?我會很感激這里的一些理論回應。
- 如何更新串列的元素?到目前為止,我的方法是重新創建整個串列,同時更新我感興趣的元素。但這種方法似乎并不高效。
uj5u.com熱心網友回復:
這與串列沒有任何關系。有意地,在 Haskell 中根本不可能更新任何值。
為什么?嗯,這只是語言的設計方式。您不妨問為什么命令式語言允許更新值。我的意思是,你寫
x = 3
然后你寫
x = 4
武漢理工大學?第一個是謊言還是什么?當然,我們應該明確指出我們指的是兩個不同的時間變數。這只是要求錯誤!當然,僅僅保存一些字符并啟用一些也可以通過其他更安全的方式實作的低級優化是不值得的?
……對不對?
即使在命令式語言中,更新(鏈接)串列中的值實際上也沒有多大意義——無論如何您都需要遍歷O ( n ) 個引數才能找到應該更改的引數。創建一個全新的串列平均只需要更改舊串列的兩倍時間,但與命令式更新不同,您永遠不需要擔心其他東西是否仍然需要舊版本,因為無論如何您都不會干擾它。?
無論如何,鏈表通常都很慢,所以擔心 2× 因素也沒有多大意義。但是,GHC 通常會完全優化串列,因此它們實際上根本不會建立在記憶體中,如果編譯器不得不擔心有人在其他地方改變串列,那么編譯器將更難保證這一點。
更新陣列中的元素,那是另一回事。事實上,更新陣列中的值在 Haskell 中也很常見,對于可以帶來重要性能提升的應用程式。仍然無法更新陣列型別的值,但可以通過對單一可變陣列的參考來更新值。這最終看起來與您在命令式語言中更新陣列的方式非常相似,盡管它通常有點冗長,因為所有陣列工具都需要從庫中匯入,而不是使用內置語法。
import qualified Data.Vector.Mutable as VM
main :: IO ()
main = do
myArray <- VM.generate 37 (const "this element isn't set yet")
print =<< VM.read myArray 0
VM.write myArray 0 "newValue"
print =<< VM.read myArray 0
等效的 Python:
def main():
myArray = ["this element isn't set yet"] * 37
print(myArray[0])
myArray[0] = "newValue"
print(myArray[0])
However, very often you don't really need to update elements. In fact, we immediately see a problem here: you're indexing into an array. That means you need to ensure the index actually exists. In imperative language, this is so common that you hardly think about it, but in Haskell we really prefer total code, i.e. even if we accidentally swap two variables (like two different loop-indices) it should not give a runtime error, but preferrably a compiler one.
More often than not, if you're updating a single element, you'll also be updating other elements. In fact, very often you'll be sequentially updating all of them, and then there isn't much advantage anymore over simply building a new list from scratch that contains the updated values right away. And with that approach, there's very little that can go wrong, at least not at runtime.
?There's a big caveat here: if somebody else still uses the old list, it means the garbage collector can't reclaim the memory. This is the reason why it's quite easy to get memory leaks in Haskell – IMO the single biggest problem of the language.
uj5u.com熱心網友回復:
應該感覺很熟悉:Python 字串的行為方式相同。你不能這樣做myString[0] = 'H',即使在 C 等其他語言中這很好。
這使得撰寫代碼更容易并有助于防止錯誤,因為您不必經常注意誰修改了哪個字串。
如果您確實想“修改”Python 字串?你不會三思而后行:
myString = 'H' myString[1:]
當然,如果您需要傳播這樣的更改,它需要您對程式進行一些重構,但總的來說它是有幫助和有效的。出于同樣的原因,Python 對數字和元組也做同樣的事情。
Haskell 的目標是更安全,因此對串列也是如此。(和地圖。和集合。還有其他一切。)
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/359162.html
下一篇:保護運算式的模式匹配
