[英]How do I get GHCi to show me an ambiguous type signature?
如果我有一個我知道有歧義類型的表達式,有沒有辦法讓 GHCi 實際上完整地告訴我那個類型,這樣我就可以看到自己的確切歧義,而不必將它的一部分拼湊起來錯誤信息? 例子:
GHCi, version 9.0.1: https://www.haskell.org/ghc/ :? for help
ghci> default ()
ghci> :t +v show . read
<interactive>:1:1: error:
• Ambiguous type variable ‘b0’ arising from a use of ‘show’
prevents the constraint ‘(Show b0)’ from being solved.
Probable fix: use a type annotation to specify what ‘b0’ should be.
These potential instances exist:
instance Show Ordering -- Defined in ‘GHC.Show’
instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
instance Show Integer -- Defined in ‘GHC.Show’
...plus 23 others
...plus 21 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In the first argument of ‘(.)’, namely ‘show’
In the expression: show . read
In the expression: show . read
<interactive>:1:8: error:
• Ambiguous type variable ‘b0’ arising from a use of ‘read’
prevents the constraint ‘(Read b0)’ from being solved.
Probable fix: use a type annotation to specify what ‘b0’ should be.
These potential instances exist:
instance Read Ordering -- Defined in ‘GHC.Read’
instance Read a => Read (Maybe a) -- Defined in ‘GHC.Read’
instance Read Integer -- Defined in ‘GHC.Read’
...plus 23 others
...plus 10 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In the second argument of ‘(.)’, namely ‘read’
In the expression: show . read
In the expression: show . read
ghci>
在那個例子中,我想要的是 GHCi 告訴我show . read :: (Show a, Read a) => String -> String
show . read :: (Show a, Read a) => String -> String
或類似的東西。
你不會讓 ghci 告訴你這種模棱兩可的類型,但別擔心。 這個show . read
show . read
example 是相當人為的,你不會在實踐中遇到它。 你至少可以從中做出一個定義
readShow :: forall a. Read a => Show a => String -> String
readShow = show @a . read @a
GHCi 為您提供您想要的信息,但不是您想要的格式。
使用-fdefer-type-errors
你會得到show . read :: String -> String
在錯誤之后show . read :: String -> String
。 你很失望它不是像show . read :: (Read a, Show a) => String -> String
那樣的東西show . read :: (Read a, Show a) => String -> String
show . read :: (Read a, Show a) => String -> String
。
問題是它不明確的全部原因是類型變量a
沒有出現在整個表達式的類型中,以便附加約束。 約束必須在表達式“內部”解決,與整體類型String -> String
無關。
GHC當然可以在類型中添加一個虛假的類型變量,比如show . read :: (Read a, Show a) => String -> String
show . read :: (Read a, Show a) => String -> String
只是為了告訴你歧義類型。 但它已經告訴你關於模棱兩可的類型,如果你真的閱讀了錯誤消息,它會告訴你:
• Ambiguous type variable ‘a0’ arising from a use of ‘show’
prevents the constraint ‘(Show a0)’ from being solved.
究竟是什么問題
Probable fix: use a type annotation to specify what ‘a0’ should be.
要修復它,您可能需要添加更多類型信息
These potential instances exist:
instance Show Ordering -- Defined in ‘GHC.Show’
instance Show Integer -- Defined in ‘GHC.Show’
instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
...plus 22 others
...plus 21 instances involving out-of-scope type
一個“潛在”實例列表,告訴您可以在它建議您可能需要的附加類型信息中使用哪些類型(誠然,這在這里不是很有用)。
• In the first argument of ‘(.)’, namely ‘show’
In the expression: show . read
問題出在哪里; 精確定位確切的子表達式(因為可以想象在同一行上可能有不止一種使用show
)。
show
是代碼中需要Show
實例的確切點,並且它應該使用什么類型來查找實例存在歧義。 不是調用的返回類型.
,這是明確的String -> String
。 這就是 GHC 告訴您的(對於下一條錯誤消息中的Read
約束也類似)。
考慮這個例子:
ghci> :t length [1] + 10
length [1] + 10 :: Int
在正常的默認規則下,這很好。 使用default ()
你會得到一個關於無法解決約束Num a0
的模棱兩可的類型錯誤。 但是看到以下類型有用嗎?
length [1] + 10 :: (Num a) => Int
我怎么知道哪里有歧義? 它是1
還是10
,還是length
可能需要一個Num
約束(它可以像genericLength
那樣genericLength
)? GHC 實際上告訴你的是1 :
• Ambiguous type variable ‘a0’ arising from the literal ‘1’
prevents the constraint ‘(Num a0)’ from being solved
這比您想要的信息更豐富。
你說你想“看到我自己的確切歧義,而不是必須從錯誤消息中拼湊出來”,但這實際上不是你所要求的。 GHC告訴你確切的不確定性(這兩個約束不能得到解決,它需要解決)。 您所要求的是在約束中查看變量的類型簽名,這些變量沒有出現在=>
的右側,以便您可以推斷出內部一定出了什么問題,而不是閱讀錯誤消息,它告訴您內部出了什么問題導致了這種情況。
大概你想要那個,因為它會更短更容易讓你識別,我當然可以理解! 我認為處理該問題的正確方法只是學習 GHC 的錯誤消息,直到您可以“模式匹配” Ambiguous type variable 'a0' arising from a use of 'read' prevents the constraint '(Read a0)' from being solved.
盡可能輕松地(Read a, Show a) => String -> String
。
1實際上, length
的返回類型明確為Int
,它將+
和10
使用的Num
約束設置為Int
,因此整個表達式明確為Int
類型。 歧義僅在於列表中1
的類型,而不在於+
的返回類型,因此結果中不應存在Num
約束。
我認為您無法讓 GHCI 告訴您。 我認為這是因為即使您打開 AllowAmbiguoustypes 以便表達式編譯,GHCI 的默認規則將可讀類型解析為()
,而不是作為類型參數。 沒有比String -> String
更有趣的類型了。 並且讓它多態是沒有意義的,因為這個函數的客戶端不可能放置一個類型注釋來指示他們想要讀取的類型。
將此與read . show
對比read . show
read . show
,哪個 GHCI 會很樂意為您提供類型,因為它可以根據給定的參數推斷要使用的類型。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.