2012-07-10 27 views
2

這應該是非常簡單的,但我似乎無法繞過它。用戶定義列表實例

假設我有我自己的List類,在其接口中聲明headtailList應該是你期望的,那是一個同質物品的集合。 然後,我想創建一個實現List接口的data類型。

下面的代碼是我想到的,但它不起作用:你會如何解決它?

class List l where                
    head :: l -> a -- ERROR! How do I tell: given a list, return an element?              
    tail :: l -> l                

data ConsList a = Nil | Cons a (ConsList a)          

instance List (ConsList Int) where            
    head Nil = error "Empty List"            
    head (Cons h _) = h               
    tail Nil = error "Empty List"            
    tail (Cons _ t) = t      

在此先感謝!

+0

只是一個元註釋:對於Haskell初學者來說,經常聲明類是有點常見的。你可能只想編寫兩個類型爲'head :: ConsList a - > a'和'tail :: ConsList a - > ConsList a'的函數,而不是類。 – 2012-07-10 15:01:58

+0

作爲一個更通用的「列表類」的例子,考慮parsec的['Stream'](http://hackage.haskell.org/packages/archive/parsec/latest/doc/html/Text-Parsec-Prim。html#t:Stream) – phg 2012-07-10 15:21:19

+0

@DanielWagner我同意你的意見!我只是通過Okasaki的書來解決這個問題,這本書解釋了許多相同接口的實現,而我在第3頁遇到了這個問題。 – lbolla 2012-07-11 13:05:31

回答

12

而不是限定List一個類型的類,把它定義爲一個構造類:

class List l where 
    head :: l a -> a 
    tail :: l a -> l a           

data ConsList a = Nil | Cons a (ConsList a) 

instance List ConsList where 
    head Nil = error "Empty List" 
    head (Cons h _) = h 
    tail Nil = error "Empty List" 
    tail (Cons _ t) = t 

可替換地,固定元件類型(注意:對於你的ConsList型,這需要靈活實例):

{-# LANGUAGE FlexibleInstances #-} 

class List l where 
    head :: l -> Int 
    tail :: l -> l 

data ConsList a = Nil | Cons a (ConsList a) 

instance List (ConsList Int) where 
    head Nil = error "Empty List" 
    head (Cons h _) = h 
    tail Nil = error "Empty List" 
    tail (Cons _ t) = t 

最後,與類型家庭,你可以做更多花哨的東西,但它真的取決於你的具體情況,如果你應該去那麼遠(可能不是):

{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE TypeFamilies  #-} 

class List l where 
    type Elt l 
    head :: l -> Elt l 
    tail :: l -> l 

data ConsList a = Nil | Cons a (ConsList a) 

instance List (ConsList Int) where 
    type Elt (ConsList Int) = Int 

    head Nil = error "Empty List" 
    head (Cons h _) = h 

    tail Nil = error "Empty List" 
    tail (Cons _ t) = t 
+0

在你的第二個例子中 - 你有'head :: l-> Int'這是一個錯字或打算,如果後者我不明白它,它只會在整數列表上工作,或者我錯過了一個點。無可否認,我還沒有遇到「靈活的實例」。 – epsilonhalbe 2012-07-10 16:52:02

+0

@epsilon'εⳆ2'halbe它的目的。它修復了抽象爲'Int'的列表的元素類型。 – 2012-07-10 18:48:19

+0

但它是正確的,所以它只適用於'List Int'和其他'head'沒有任何意義,並且所有好的多態性都會消失? – epsilonhalbe 2012-07-10 19:36:17

3

使過列表的一個抽象的最簡單方法是抽象的過度類型構造,即,過[],沒有結束[a](這是語法糖[] a)。

,以便類變爲:

class List l where 
    head :: l a -> a -- now l is applied to the element type 
    tail :: l a -> l a 

那麼您的實例相應地改變:

instance List ConsList where 
    ... -- code as before 
7

可以

  • 使它成爲一個構造器類,

    class List l where 
        head :: l a -> a 
        tail :: l a -> l a 
    
  • 使其成爲多參數類型類函數依賴

    class List l a | l -> a where 
        head :: l -> a 
        tail :: l -> l 
    
  • 使用類型家庭

    class List l where 
        type Elem l 
        head :: l -> Elem l 
        tail :: l -> l 
    

我考慮構造類去了解它的最佳方式。