Parsing 理解读取实例

Parsing 理解读取实例,parsing,haskell,Parsing,Haskell,我对我的数据进行了Read和Show实例,但不理解Read实例 data Tests = Zero | One Int | Two Int Double instance Show Tests where show Zero = "ZERO" show (One i) = printf "ONE %i" i show (Two i j) = printf "TWO %i %f" i j instance Read Tests

我对我的数据进行了
Read
Show
实例,但不理解
Read
实例

data Tests = Zero
          | One Int
          | Two Int Double

instance Show Tests where
  show Zero      = "ZERO"
  show (One i)   = printf "ONE %i" i
  show (Two i j) = printf "TWO %i %f" i j

instance Read Tests where
  readsPrec _ str   = [(mkTests str, "")]

mkTests :: String -> Tests
mkTests = check . words

check :: [String] -> Tests
check ["ZERO"]      = Zero
check ["ONE", i]    = One (read i)
check ["TWO", i, j] = Two (read i) (read j)
check _             = error "no parse"

main :: IO ()
main = do
  print Zero
  print $ One 10
  print $ Two 1 3.14

  let x = read "ZERO" :: Tests
  print x
  let y = read "ONE 2" :: Tests
  print y
  let z = read "TWO 2 5.5" :: Tests
  print z
这是输出

ZERO         
ONE 10       
TWO 1 3.14   
ZERO         
ONE 2        
TWO 2 5.5  
以下是问题:

  • 建议采用什么方法来实现
    读取
    实例

    • Read
      类的最小完整定义是
      readsPrec | readPrec
      readPrec::readPrec编写的描述
    建议使用新型解析器(仅限GHC)替换readsPrec

    • 我应该使用
      readPrec
      吗?如何使用?我在网上找不到任何我能理解的例子
    • 什么是
      新型解析器
      ,它是
      parsec
  • 的第一个
    Int
    参数用于什么

  • 是否有任何方法可以从
    Show
    中派生
    Read

  • 在过去,我可以使用
    派生(Show,Read)
    来完成大部分工作。但这次我想进入下一个阶段

  • 在我看来,实现Read的正确方法是派生它,否则,最好使用更复杂的解析器。这是你所有问题的答案。
    • readPrec是GHC提供的一种基于解析器组合器的简单方法。如果您愿意为您的Read实例牺牲可移植性,那么您可以使用它,这会使解析变得更容易
    • 我在下面提供了一个如何使用readPrec的小示例
    • parsec与readPrec不同,但两者都类似于解析器组合器。是一个更完整的解析器库。另一个解析器组合器库是,它的工作原理与parsec非常类似
    • parsec和AttorParsec不能与普通的ReadTypeClass一起使用(至少是直接使用),但它们提供的更大的灵活性使它们在需要更复杂的解析时成为一个好主意
  • readsPrec
    Int
    参数用于解析时处理优先级。当您想要解析算术表达式时,这可能很重要。如果优先级高于当前运算符的优先级,则可以选择解析失败
  • 不幸的是,从
    Show
    派生
    Read
    是不可能的
  • 下面是几个代码片段,展示了如何使用
    ReadPrec
    实现
    Read

    ReadPrec示例:

    instance Read Tests where
      readPrec = choice [pZero, pOne, pTwo] where
        pChar c = do
          c' <- get
          if c == c'
          then return c
          else pfail
        pZero = traverse pChar "ZERO" *> pure Zero
        pOne = One <$> (traverse pChar "ONE " *> readPrec)
        pTwo = Two <$> (traverse pChar "TWO " *> readPrec) <*> readPrec
    
    实例读取测试,其中
    readPrec=选择[pZero,pOne,pTwo]其中
    pChar c=do
    
    对于这样一个简单的语法,推荐一个功能齐全的解析器有点傻(就像推荐用机关枪捕鸟一样)。没有规则规定
    Show
    /
    Read
    不能用于自定义语法(实际上,任何带有
    Show
    实例的抽象类型都必须使用自定义语法)。无法用于实现自定义语法的是派生实例,但OP声明它们未使用派生实例。如果您回答
    1,我将编辑为问题编号。
    您能提供工作代码吗?