Implementing `read` for a left-associative tree in Haskell

后端 未结 3 1342
时光说笑
时光说笑 2020-12-30 11:39

I\'m having a hard time implementing Read for a tree structure. I want to take a left-associative string (with parens) like ABC(DE)F and convert it into a tree.

3条回答
  •  庸人自扰
    2020-12-30 12:18

    The parsec answer by dbaupp is very easy to understand. As an example of a "low-level" approach, here is a hand written parser which uses a success continuation to handle the left-associative tree building:

    instance Read Tree where readsPrec _prec s = maybeToList (readTree s)
    
    type TreeCont = (Tree,String) -> Maybe (Tree,String)
    
    readTree :: String -> Maybe (Tree,String)
    readTree = read'top Just where
      valid ')' = False
      valid '(' = False
      valid _ = True
    
      read'top :: TreeCont -> String -> Maybe (Tree,String)
      read'top acc s@(x:ys) | valid x =
        case ys of
          [] -> acc (Leaf x,[])
          (y:zs) -> read'branch acc s
      read'top _ _ = Nothing
    
      -- The next three are mutually recursive
    
      read'branch :: TreeCont -> String -> Maybe (Tree,String)
      read'branch acc (x:y:zs) | valid x = read'right (combine (Leaf x) >=> acc) y zs
      read'branch _ _ = Nothing
    
      read'right :: TreeCont -> Char -> String -> Maybe (Tree,String)
      read'right acc y ys | valid y = acc (Leaf y,ys)
      read'right acc '(' ys = read'branch (drop'close >=> acc) ys
         where drop'close (b,')':zs) = Just (b,zs)
               drop'close _ = Nothing
      read'right _ _ _ = Nothing  -- assert y==')' here
    
      combine :: Tree -> TreeCont
      combine build (t, []) = Just (Branch build t,"")
      combine build (t, ys@(')':_)) = Just (Branch build t,ys)  -- stop when lookahead shows ')'
      combine build (t, y:zs) = read'right (combine (Branch build t)) y zs
    

提交回复
热议问题