簡體   English   中英

如果沒有FlexibleContexts,使用Char不會編譯

[英]Using Char does not compile without FlexibleContexts

sierpinski :: Int -> Array (Int,Int) Char
sierpinski l = runSTArray $ do
  arr <- newArray ((1,1),(63,32)) '_'
  let drawLine x y len = forM_ [-len..len] $ \s -> writeArray arr (x+s,y-len) '1' --this part does not compile without FlexibleContexts \\* Non type-variable argument in the constraint: MArray a0 Char m (Use FlexibleContexts to permit this)
  let rek n x y h | n == 0 = forM_ [0..h-1] (drawLine x y)
                  | otherwise = do
                    rek (n-1) x y (div h 2)
                    rek (n-1) (x + div h 2) (y - div h 2) (div h 2)
                    rek (n-1) (x - div h 2) (y - div h 2) (div h 2)
  rek l 32 32 32
  return arr

但是將數組類型從Char更改為Int是可以的

sierpinski :: Int -> Array (Int,Int) Int
sierpinski l = runSTArray $ do
  arr <- newArray ((1,1),(63,32)) 0
  let drawLine x y len = forM_ [-len..len] $ \s -> writeArray arr (x+s,y-len) 1 --now ok
  let rek n x y h | n == 0 = forM_ [0..h-1] (drawLine x y)
                  | otherwise = do
                    rek (n-1) x y (div h 2)
                    rek (n-1) (x + div h 2) (y - div h 2) (div h 2)
                    rek (n-1) (x - div h 2) (y - div h 2) (div h 2)
  rek l 32 32 32
  return arr

有人可以澄清為什么會這樣嗎?

謝謝。

原因實際上是在錯誤消息中。

Non type-variable argument in the constraint: 
  MArray a0 Char m (Use FlexibleContexts to permit this)

當您使用文字'_''1' ,Haskell推斷它們的類型是Char ,然后它會遇到MultiParamTypeClasses約束所帶來的最典型問題 - 約束參數不是所有類型變量,但是是Haskell報告要求它們。 簽名Haskell 想要推斷的是類似的東西

drawLine :: MArray a Char m => ...

這在MultiParamTypeClasses之前不是問題,因為之前的所有類只有一個參數。 然后,如果該參數不是類型變量,那么您所要做的就是檢查該實例是否是可派生的,如果它類型變量,則將其保留為約束。 使用MultiParamTypeClasses您經常會遇到中間情況 - 某些參數是實例化的,有些則不是。 FlexibleContexts讓你有這種混合(甚至更多)。 這是一個安全的擴展(我希望看到它成為Haskell 2020的一部分)。

但是Int呢? 為什么不給我同樣的錯誤?

它實際上不是直接關於Int 當Haskell看到文字01 ,由於數字文字被重載,它只決定一般類型: Num a => a 這意味着約束Haskell推斷的只是

drawLine :: (Num n, MArray a n m) => ...

這甚至不需要FlexibleInstances因為所有約束都具有類型變量的參數。

只是一個基於我理解的想法 - 當你傳遞一個Char值時,它已經是一個'專業'類型。 另一方面,由於您在沒有明確鍵入的情況下傳入數字,我相信可以解釋為傳遞更通用的類型,即(Num a) => a 這就是為什么GHC抱怨明確的Char字面,但不是數字。

基於我對文檔的理解基於

Haskell為let或where綁定的每個變量計算一個類型,然后概括這個類型。 在Haskell 98中,允許的上下文是受限制的,因此使用實例聲明減少了上下文(並且刪除了重復的斷言和類上下文隱含的那些),直到它們處於允許的形式或者沒有適用的實例,在這種情況下錯誤是報道。

暫無
暫無

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

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