2012-06-12 89 views
3

我開始用GHC 7.4.2中的新類約束擴展來弄溼我的腳,但是我有一些問題需要一個小例子來工作。代碼如下:haskell約束系列

{-# LANGUAGE UndecidableInstances, 
     MultiParamTypeClasses, 
     KindSignatures, 
     TypeFamilies, 
     Rank2Types, 
     ConstraintKinds, 
     FlexibleInstances, 
     OverlappingInstances #-} 

module Test where 

    import GHC.Exts -- to get Constraint type constructor 

    class NextClass f where 
    type Ctxt f a :: Constraint 
    next :: (Ctxt f a) => a -> a 

    instance NextClass Int where 
    type Ctxt Int a = Num a 
    next b = b + 1 

    n :: (NextClass a) => a -> a 
    n v = next v 

我想要做的就是定義一個NextClass類型的類,這將讓我(給定值x)得到X的下一個值是的情況下,所有類型是什麼NextClass。要使用+運算符,我需要Num a類約束Int

然而,GHC給了我以下錯誤:

Could not deduce (Ctxt f0 a) arising from a use of `next' 
from the context (NextClass a) 
    bound by the type signature for n :: NextClass a => a -> a 
In the expression: next v 
In an equation for `n': n v = next v 

我懷疑GHC告訴我,它沒有足夠的信息來確定要使用的約束族實例。

有人可以解釋我在做什麼錯在這裏。這是限制家庭的正確使用嗎?

TIA

回答

5

你的定義中有一些奇怪的事情發生。首先,(只)類方法next的類型從未提及類變量f。編譯器應該如何選擇使用哪個類型的實例?我要去承擔你的意思是這樣的:

{-# LANGUAGE ConstraintKinds, TypeFamilies #-} 
module Test where 

import GHC.Exts -- to get Constraint type constructor 

class NextClass f where 
    type Ctxt f :: Constraint 
    next :: Ctxt f => f -> f 

instance NextClass Int where 
    type Ctxt Int = Num Int 
    next b = b + 1 

n :: (NextClass a) => a -> a 
n v = next v 

接下來的奇異之處在於Int已經有一個Num實例,所以這是沒有太大的約束。但是,讓我們離開那個放在一邊(因爲它不會影響我們得到的錯誤),只是看看新的錯誤:

test.hs:15:7: 
    Could not deduce (Ctxt a) arising from a use of `next' 
    from the context (NextClass a) 
     bound by the type signature for n :: NextClass a => a -> a 
     at test.hs:15:1-12 
    In the expression: next v 
    In an equation for `n': n v = next v 

其實,這個錯誤是非常明智的:約束的整點是,有一個NextClass a的實例是不夠的;我們還必須有一個Ctxt a的實例。所以我們可以修復類型簽名:

n :: (NextClass a, Ctxt a) => a -> a 
n v = next v 

...然後它編譯。最後的奇異之處在於這是一個特別退化使用約束類型的,因爲這簡單的代碼基本上是等價的:

class NextClass f where 
    next :: f -> f 

instance Num Int => NextClass Int where 
    next b = b + 1 

...並從以前的事了新的東西翻譯是很機械的:不是聲明instance NextClass {- foo -} where type Ctxt {- foo -} = {- bar -},您只需寫入instance {- bar -} => NextClass {- foo -}

+0

感謝丹尼爾,我改變了我的代碼使用'實例Num Int => NextClass Int其中...'。這是在Haskell中編寫這種類型代碼的慣用方法嗎? –

+0

@RananvanDalen那麼,慣用的方法是'實例NextClass Int其中...'沒有無約束的約束或'newtype SuccNext a = SuccNext a;實例Num a => NextClass(SuccNext a)其中...具有多態類型(以及防止虛假重疊的新類型)。 –

+0

好東西。我必須再讀一遍類型類:) –