如果一個運算式可以用多種方式輸入,Haskell 如何選擇使用哪一種?
激勵例子
舉個例子:
$ ghci
GHCi, version 8.8.4: https://www.haskell.org/ghc/ :? for help
Prelude> import Data.Ratio (Ratio)
Prelude Data.Ratio> f z s = show $ truncate $ z (read s)
Prelude Data.Ratio> :type f
f :: (RealFrac a, Read a) => a -> String -> String
Prelude Data.Ratio> s = take 30 (cycle "12345")
Prelude Data.Ratio> s
"123451234512345123451234512345"
Prelude Data.Ratio> f 0 s
"123451234512345121227855101952"
Prelude Data.Ratio> f (0::Double) s
"123451234512345121227855101952"
Prelude Data.Ratio> f (0::Float) s
"123451235679745417161721511936"
Prelude Data.Ratio> f (0::Ratio Integer) (s "%1")
"123451234512345123451234512345"
Prelude Data.Ratio> show $ truncate $ read s
"123451234512345121227855101952"
當我不使用0任何型別時,我得到與 for 相同的結果(0::Double)。所以在我看來,當我呼叫 時f 0 s,它使用了一個read產生 aDouble的版本,而一個版本truncate將它Double變成了某種整數型別。我介紹了變數z,以便我可以輕松控制這里的型別。有了這個,我可以證明其他解釋是可能的,例如使用Float或精確的比率。那為什么Double?最后一行省略了加法,表明行為與零常數無關。
我猜有些東西告訴 Haskell 這Double是一個比其他型別更規范的型別,無論是一般情況下還是用作 a 時,所以如果它可以使用作為中間結果RealFrac的運算式解釋,而且還有其他一些型別,那么它會更喜歡這種解釋。DoubleDouble
核心問題
- 我的解釋觀察到的行為是否正確,這里有一個隱式型別默認值?
- 這種偏好的名稱是什么?
- 有沒有辦法禁用這種規范型別的選擇并為可以以多種方式解釋的事物強制執行顯式型別規范?
自己的研究
我讀過https://en.wikibooks.org/wiki/Haskell/Type_basics_II#Polymorphic_guesswork寫道
在沒有其他限制的情況下,5.12 將采用默認的分數型別 Double,因此 (-7) 也將成為 Double。
這似乎證實了我的假設,即Double在某種程度上被祝福為某些父類別的默認型別RealFrac。它仍然沒有提供該概念的名稱,也沒有提供有關該概念的完整規則串列。
背景
我真正想要處理的情況更像是這樣的:
f :: Integer -> String -> Integer
f scale str = truncate $ (fromInteger scale) * (read str)
所以我想要一個函式,它接受一個字串,將它作為小數讀取,將它與給定的數字相乘,然后將結果截斷回一個整數。我很驚訝地發現編譯時無需我在任何地方指定中間小數型別。
uj5u.com熱心網友回復:
如果存在v帶有Num v約束的模棱兩可的型別變數,則默認為Integeror Double,按該順序嘗試,以滿足 上的所有其他約束為準v。
Haskell 報告中解釋了這些默認規則:https ://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-620004
GHC 手冊還解釋了 GHCi 中的其他默認規則(這意味著在 GHCi 中嘗試不會讓您準確了解編譯程式時發生的情況):https ://downloads.haskell.org/ghc/latest/ docs/html/users_guide/ghci.html#type-defaulting-in-ghci
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/427283.html
上一篇:執行執行緒中的`f::a->IO()`評估:Haskell
下一篇:如何在串列中獲取多個第n個元素?
