簡體   English   中英

Haskell - 重疊實例和轉換類型類

[英]Haskell - Overlapping Instances and Conversion typeclass

我正在編寫代碼以通過數學邏輯中的定義來實現擴展

它接受語言及其擴展的描述,並輸出一個新的 haskell 文件,該文件會將高級語言解析為低級語言。 當然,如果我可以將語言 C 轉換為語言 B,將語言 B 轉換為語言 A,那么通過組合我可以將 C 轉換為 A....

這是我面臨的問題的一個最小示例:

data A = EmptyA | NodeA A A
data B = EmptyB | NodeB B B | UnaryB B
data C = EmptyC | NodeC C C | UnaryC C | TernaryC C C C


class ToA a where
  convertToA :: a -> A

class ToB a where
  convertToB :: a -> B


instance ToA B where
  convertToA EmptyB      = EmptyA
  convertToA (NodeB l r) = NodeA (convertToA l) (convertToA r)
  convertToA (UnaryB l)  = NodeA (convertToA l) EmptyA

instance ToB C where
  convertToB EmptyC           = EmptyB
  convertToB (NodeC l r)      = NodeB (convertToB l) (convertToB r)
  convertToB (UnaryC l)       = UnaryB (convertToB l)
  convertToB (TernaryC l m r) = NodeB (convertToB l) (NodeB (convertToB m) (convertToB r))


-- instance (ToB a) => ToA a where
--   convertToA = convertToA . convertToB

-- I shouldn't have to write this
instance ToA C where
  convertToA  = convertToA . convertToB

直觀地說, instance (ToB a) => ToA a沒有什么問題,但是編譯器不喜歡它。 代碼按原樣編譯,但在用注釋版本替換顯式ToA C實例后,我收到以下錯誤:


minimal.hs:25:21: error:
    • Illegal instance declaration for ‘ToA a’
        (All instance types must be of the form (T a1 ... an)
         where a1 ... an are *distinct type variables*,
         and each type variable appears at most once in the instance head.
         Use FlexibleInstances if you want to disable this.)
    • In the instance declaration for ‘ToA a’
   |
25 | instance (ToB a) => ToA a where
   |                     ^^^^^

當然,我不懼怕語言擴展,所以我照我說的做了,並添加了 FlexibleInstances,盡管我認為它在這里沒有幫助。 完成此操作后,我被告知嘗試 UndecidableInstances ......這就是線索停止的地方。 我仍然收到類型錯誤,但我不確定該怎么做。

minimal.hs:29:16: error:
    • Overlapping instances for ToA B
        arising from a use of ‘convertToA’
      Matching instances:
        instance ToB a => ToA a -- Defined at minimal.hs:28:10
        instance ToA B -- Defined at minimal.hs:16:10
    • In the first argument of ‘(.)’, namely ‘convertToA’
      In the expression: convertToA . convertToB
      In an equation for ‘convertToA’:
          convertToA = convertToA . convertToB
   |
29 |   convertToA = convertToA . convertToB
   |                ^^^^^^^^^^

這個錯誤消息讓我特別困惑,因為我只有一個ToA B定義。 如果B本身就是ToB的一個實例,例如通過設置convertToB = id ,這個錯誤會更有意義。 當然,這里不是這樣的……

我應該如何正確處理這個問題? 提前致謝! ^_^

你在做正確的事情。 你對Overlapping instances警告保持謹慎是正確的。 在這種情況下,它是連貫的。 而且你不害怕語言擴展,所以你想要:

instance {-# OVERLAPPABLE #-} (ToB a) => ToA a where
  convertToA = convertToA . convertToB

{-# #-}中的那個東西是一個編譯指示,它是一種專門針對這種情況調用語言擴展的方法。 OVERLAPPABLE意味着允許有一個更具體的實例( ToA B ),並根據偏好選擇它。

您的約束(ToB a) =>確實是Undecidable ,因為它不小於實例頭。 與重疊相比, UndecidableInstances是一個相對“安全”的擴展。

對於重疊,不安全的使用是INCOHERENT的(就像聽起來一樣糟糕)或“孤兒實例”——有時會給你一個編譯器警告; 不適用於此處,因為您的所有實例都與 class 聲明位於同一模塊中。

暫無
暫無

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

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