2013-10-17 81 views
1

Haskell的新品嚐試編寫解析器。Haskell Typeclasses:我在這裏做錯了什麼?

我已經使用attoparsec成功地將我的輸入文件劃分爲AST中的標記。

我現在想要走AST並從它發出輸出。我認爲我可以通過從類型類派生一些通用例程給Token類,然後在實例中根據Token類型發出代碼時根據需要提供特定函數。

該代碼可能比我的解釋更容易遵循。這是我的嘗試:

class AST a where 
    children :: a -> [a] 
    prefix :: a -> String 
    suffix :: a -> String 
    node :: a -> [String] 

    children v = [] 
    prefix v = "" 
    suffix v = "" 
    node v = [prefix v] ++ (concatMap node $ children v) ++ [suffix v] 

data Token = Line { lnName :: String, lnLines :: Int } 
      | LineList { llLines :: [Token] } 
      | Init String 
      | Main String 
      | Step { stId :: String, stDuration :: Float } 
      | Scene { scId :: String, scTokens :: [Token] } 
      | Sequence { sqId :: String , sqScenes :: [Token] } 
      | File {flContents :: [Token]} deriving (Show, AST) 

所以我的理解是,如果我從類型類派生我已經寫了:

  • 我並不需要提供一個實例定義爲所有的該功能具有默認實現
  • 我可以根據需要

覆蓋每個令牌類型的默認設置,但是我從GHC一個錯誤,也沒有那麼有用

Parser.hs | 27 col 60 error |不能派生實例AST Token': AST'不是衍生類在'令牌'的數據聲明中

不夠公平,但爲什麼會這樣呢?不知道如何解決問題而不知道有什麼信息。任何幫助感激地收到。

我知道這不是一個有用的評論,但我不得不說,絕對愛哈斯克爾。這是一個快樂的學習:)

+2

當心。 Haskell類型類與平均OO語言中的類非常不同。 「派生」只是幫助某些實例變得微不足道(但是討厭,因爲如此廣泛),甚至更容易定義,除此之外別無其他;一般的方式仍然是'實例'。 - 就你而言,我想知道你是否應該使用類型類 - 也許只是另一個「數據」會更好。 – leftaroundabout

+4

順便說一下,在這種情況下使用類型類型絕對沒有優勢。還有哪些其他實例?所有實例遵循哪些規則,以便可以推理有界多態?如果你想在這裏使用多態,可以在'Token'類型上引入一個類型變量,並使用參數多態。 – Carl

+0

嗨,感謝您的評論。我已經將代碼gen實現爲個別類型重載函數。不利的一面是我結束了幾分樣板,我不想和所以我想用默認功能 –

回答

5

deriving可用於limited, fixed list of typeclass。這裏的問題是,你需要告訴編譯器,你所定義的函數是AST類的實例的數據類型Token,就像這樣:

class AST a where 
    children :: a -> [a] 
    prefix :: a -> String 
    suffix :: a -> String 
    node :: a -> [String] 

instance AST Token where 
    children v = [] 
    prefix v = "" 
    suffix v = "" 
    node v = [prefix v] ++ (concatMap node $ children v) ++ [suffix v] 

data Token = Line { lnName :: String, lnLines :: Int } 
      | LineList { llLines :: [Token] } 
      | Init String 
      | Main String 
      | Step { stId :: String, stDuration :: Float } 
      | Scene { scId :: String, scTokens :: [Token] } 
      | Sequence { sqId :: String , sqScenes :: [Token] } 
      | File {flContents :: [Token]} 
      deriving (Show) 
+0

阿類型類的方式我看。這是一個恥辱,感覺有點哈克。我希望,如果你創建了一個提供的所有默認功能,你可以將它添加到您的派生列表類型的類,我不知道這是一個固定列表:( –

+1

這不是哈克,作爲問題的評論說明,類型類是有用的,當你將有很多不同的情況下,通常並不是微不足道的。'因爲編譯器現在怎麼*派生*實例(使其適應具體數據)。在你的榜樣,有什麼可得出deriving'是有用。 – Nicolas

+0

對不起,我的意思不是你的解決方案但哈斯克爾只允許導出子句中預先定義的類閱讀你的鏈接,他們實際上做的相同點結論是不夠公平的是:。d >這條規定的特殊的「魔法「功能合成爲一組有限的預定義類的違背一般哈斯克爾理念使‘建在事情沒有特別的。’但是,它會節省很多的TY平。模板Haskell的實驗工作正在研究如何將這種魔法(或類似的東西)擴展到所有類。 –

2

感謝Nicolas的解釋,即派生只適用於一特定的特定類集我已經解決了我的問題。我的解決辦法是從尼古拉斯的在稍有不同的我仍然可以在AST保留通用的功能,而不是比分扳成令牌

class AST a where 
    children :: a -> [a] 
    prefix :: a -> String 
    suffix :: a -> String 
    node :: a -> [String] 

    children _ = [] 
    prefix _ = "" 
    suffix _ = "" 
    node v = [prefix v] ++ (concatMap node $ children v) ++ [suffix v] 

data Token = Line { lnName :: String, lnLines :: Int } 
      | LineList { llLines :: [Token] } 
      | Init String 
      | Main String 
      | Step { stId :: String, stDuration :: Float } 
      | Scene { scId :: String, scTokens :: [Token] } 
      | Sequence { sqId :: String , sqScenes :: [Token] } 
      | File {flContents :: [Token]} deriving (Show) 

instance AST token where 
    -- per token overides added here 
    -- defaults run if none supplied 

謝謝大家

相關問題