1

全新的 Haskell 并尝试编写解析器。

我已经使用 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)

所以我的理解是,如果我从我写的类型类派生:

  • 我不需要提供实例定义,因为所有函数都有默认实现
  • 如果需要,我可以覆盖每个 Token 类型的默认值

但是我从 ghc 得到一个错误,这并不是很有帮助

Parser.hs|27 col 60 错误| Can't make a derived instance of AST Token':AST' is not a derivable class 在“Token”的数据声明中

很公平,但为什么会这样呢?在没有更多信息的情况下如何修复它有点不知所措。感激地收到任何帮助。

我知道这不是一个有用的评论,但我不得不说,绝对喜欢 Haskell。学习是一种快乐:)

4

2 回答 2

5

deriving可用于有限的、固定的 typeclass 列表。这里的问题是您需要告诉编译器您定义的函数是ASTdatatype的类的实例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)
于 2013-10-17T05:59:36.337 回答
2

感谢 Nicolas 的解释,即派生仅适用于一组特定的类型类,我已经解决了我的问题。我的解决方案与 Nicolas 的解决方案略有不同,因为我仍然可以在 AST 中保留通用功能,而不是将其绑定到 Token

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

谢谢大家

于 2013-10-17T06:38:46.613 回答