首页 文章

Haskell Typeclasses:我在这里做错了什么?

提问于
浏览
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)

所以我的理解是,如果我从类型类派生出来,那么我写道:

  • 我不需要提供实例定义,因为所有函数都有默认实现

  • 如果需要,我可以覆盖每个令牌类型的默认值

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

Parser.hs | 27 col 60错误|无法生成AST Token'的派生实例':''''不是可派生类在“令牌”的数据声明中

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

我知道这不是一个有用的评论,但我必须说,绝对爱Haskell . 学习是一种快乐:)

2 回答

  • 5

    deriving 可用于limited, fixed list of typeclass . 这里的问题是你需要告诉编译器你定义的函数是数据类型 Token 的类 AST 的实例,如下所示:

    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)
    
  • 2

    感谢Nicolas的解释,派生仅适用于特定的类型集,我已经解决了我的问题 . 我的解决方案与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
    

    感谢大家

相关问题