2015-06-29 21 views
1

給定以下代碼,從go類型中刪除forall a r將失敗,並顯示「重疊實例用於可鍵入(D r)」。我想知道爲什麼?當存在不定量方法時重疊實例錯誤的原因

{-# LANGUAGE DeriveDataTypeable #-} 
{-# LANGUAGE ExistentialQuantification #-} 
{-# LANGUAGE FlexibleContexts #-} 
{-# LANGUAGE ScopedTypeVariables #-} 
{-# LANGUAGE StandaloneDeriving #-} 
{-# LANGUAGE TypeFamilies #-} 
module M where 

import Data.Typeable (Proxy, Typeable, cast) 

class C r where 
    data D r :: * 

deriving instance Typeable D 

data A = forall r . A (D r) 

go :: forall r a . (Typeable a, Typeable (D r)) => a -> Proxy r -> A 
go a _ = case cast a of 
    Just (b :: D r) -> A b 
    Nothing -> error "fail to cast" 

錯誤還表示,「這一決定取決於r實例化」 - 但不是由提供Proxy r寄託?

回答

4

這是範圍化類型變量在Haskell中的工作方式。請注意,您在這裏r重新使用:

go :: forall r a . (Typeable a, Typeable (D r)) => a -> Proxy r -> A 
go a _ = case cast a of 
    Just (b :: D r) -> A b -- this r is the same as the r above 

沒有明確forall,類型變量被解釋爲是本地的簽名。也就是說,您的代碼被讀爲:

go :: (Typeable a1, Typeable (D r1)) => a1 -> Proxy r1 -> A -- renaming local variables 
go a _ = case cast a of 
    Just (b :: D r) -> A b -- r bears no relation to r1 

因此,類型錯誤。

(這混亂得到一個Overlapping instances錯誤,雖然)。

+1

謝謝!如果發出警告「你使用了一個同名的類型變量,你打算添加嗎?」確實很好。 – ron

+0

@ron我強烈同意。我甚至會更改Haskell定義,以便在默認情況下啓用作用域類型變量,無論有沒有。這會破壞兼容性,但我真的很想知道這會破壞多少(我不知情的猜測是非常少的)。 – chi

相關問題