簡體   English   中英

為什么Haskell隱藏具有相同名稱但不同類型簽名的函數?

[英]Why does Haskell hide functions with the same name but different type signatures?

假設我要在字符串上定義(+) ,而不是通過給出Num String的實例。

為什么Haskell現在隱藏Num s (+)函數? 畢竟,我提供的功能:

(+) :: String -> String -> String

可以通過編譯器從Prelude (+)區分出來。 為什么兩個函數不能存在於同一名稱空間中,而是具有不同的非重疊類型簽名?

只要代碼中沒有調用函數,Haskell就會關心有一個ambiguitiy。 然后,使用參數調用函數將確定類型,以便可以選擇適當的實現。

當然,一旦有一個實例Num String ,就會發生沖突,因為在那時Haskell無法根據參數類型決定選擇哪個實現,如果實際調用了該函數。
在這種情況下,應該引發錯誤。

這不會允許函數重載而沒有陷阱/模糊嗎?

注意:我不是在談論動態綁定。

Haskell根本不支持函數重載(除了通過類型類)。 其中一個原因是函數重載不適用於類型推斷。 如果你有像fxy = x + y這樣的代碼,那么Haskell如何知道xy是Nums還是字符串,即f的類型是否應該是f :: Num a => a -> a -> af :: String -> String -> String

PS:這與你的問題並不真正相關,但是如果你假設一個開放的世界,那么類型並不是嚴格不重疊的,即在某個模塊某個地方可能有一個Num String的實例,當它被導入時會破壞你的代碼。 所以Haskell根本不會根據給定類型沒有給定類型類的實例做出任何決定。 當然,即使沒有涉及類型類,函數定義也會隱藏其他具有相同名稱的函數定義,正如我所說:與您的問題不相關。


關於為什么必須在定義站點知道函數的類型而不是在調用站點推斷它:首先,函數的調用站點可能在與函數定義不同的模塊中(或者在多個模塊中)不同的模塊),所以如果我們必須查看調用站點以推斷函數的類型,我們必須跨模塊邊界執行類型檢查。 那就是在對模塊進行類型檢查時,我們還必須完成導入該模塊的所有模塊,因此在最壞的情況下,每次更改單個模塊時都必須重新編譯所有模塊。 這將使編譯過程變得非常復雜和變慢。 更重要的是,它將使編譯庫成為不可能,因為庫的本質是它們的函數將被編譯器在編譯庫時無法訪問的其他代碼庫使用。

只要沒有調用該函數

在某些時候,使用該功能

不不不。 在Haskell中你不會想到“之前”或“你做的那一刻......”,而是一勞永逸地定義東西。 這在變量的運行時行為中最為明顯,但也轉換為函數簽名和類實例。 這樣,您不必對編譯順序進行所有繁瑣的思考,並且從許多方面都是安全的,例如C ++模板/重載經常因程序中的微小變化而破壞性。

另外,我不認為你完全理解Hindley-Milner的作品。

在調用函數之前,您知道參數的類型,它不需要知道。

好吧,你通常知道參數的類型! 它有時可以明確給出,但通常是從其他參數或返回類型推導出來的。 例如,在

map (+3) [5,6,7]

編譯器不知道數字文字有什么類型,它只知道它們是數字。 通過這種方式,您可以將結果評估為您喜歡的任何內容,並且允許您只能在其他語言中使用的內容,例如符號類型

> map (+3) [5,6,7] :: SymbolicNum
[SymbolicPlus 5 3, SymbolicPlus 6 3, SymbolicPlus 7 3]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM