簡體   English   中英

如何讓 GHCi 向我顯示不明確的類型簽名?

[英]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.

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