![](/img/trans.png)
[英]What are the pitfalls of using FlexibleContexts and FlexibleInstances?
[英]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看到文字0
和1
,由於數字文字被重載,它只決定一般類型: 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.