Haskell解析器到AST数据类型 - 输入“|”时解析错误

时间:2012-10-05 14:43:07

标签: parsing haskell

我正在努力完成我们给予的任务。我在这里根据不同的指南略微编写了这段代码:Not in scope: data constructor

我遇到的问题是这里的管道:

| x == "+" = (Sum y y',xs'') where

问题似乎与3个管道或管道跟在“哪里”有关。如果我交换最后2个管道。 放

x == "+"  = (Sum y y' (...))

之前

x == "*"  = (Prod y y' (...))

导致错误移动到该代码。如果我注释掉这两个代码段中的任何一个,一切正常,但我需要它们来完成我们给出的赋值。

快速摘要:

| x == "*" = (Prod y y',xs'') where
                (y,xs') = ast xs
                (y',xs'') = ast xs'

| x == "+" = (Sum y y',xs'') where
                (y,xs') = ast xs
                (y',xs'') = ast xs'

两者都单独工作,但当我把它们放在一起时,我的程序无法编译。

完整代码:

import Data.Char

data AST = Leaf Int 
            | Sum AST AST 
            | Min AST 
            | Prod AST AST
            deriving Show

tokenize::String -> [String]
tokenize[] = []
tokenize('+':xs) = "+": tokenize xs
tokenize('-':xs) = "-": tokenize xs
tokenize('*':xs) = "*": tokenize xs
tokenize(x:xs) = if isDigit x then (takeWhile isDigit (x:xs)) : tokenize (dropWhile isDigit xs) else tokenize(xs)

ast :: [String] -> (AST,[String])
ast [] = error "Empty string"
ast (x:xs) | all isDigit x = (Leaf (read x),xs)
    | x == "-" = let (y,xs') = ast xs in (Min y,xs')
    | x == "*" = (Prod y y',xs'') where
            (y,xs') = ast xs
            (y',xs'') = ast xs'
    | x == "+" = (Sum y y',xs'') where
            (y,xs') = ast xs
            (y',xs'') = ast xs'

2 个答案:

答案 0 :(得分:7)

中的问题
ast [] = error "Empty string"
ast (x:xs) | all isDigit x = (Leaf (read x),xs)
    | x == "-" = let (y,xs') = ast xs in (Min y,xs')
    | x == "*" = (Prod y y',xs'') where
            (y,xs') = ast xs
            (y',xs'') = ast xs'
    | x == "+" = (Sum y y',xs'') where
            (y,xs') = ast xs
            (y',xs'') = ast xs'

是函数定义中每个方程只能有一个where子句。因此,在where替代中的x == "*"之后,解析器期望模式(x:xs)的等式完成。

只需删除有问题的wherewhere子句的范围是等式中的所有备选方案,并且两个where子句具有相同的内容(并且缩进更好,{根据我的偏好,{1}}属于自己的行。由于第一个备选方案中的where使用了let子句中也存在的绑定,因此也可以删除:

where

答案 1 :(得分:1)

这样做的一种方法是使用let代替where

ast :: [String] -> (AST,[String])
ast [] = error "Empty string"
ast (x:xs) | all isDigit x = (Leaf (read x),xs)
    | x == "-" = let (y,xs') = ast xs in (Min y,xs')
    | x == "*" = let
            (y,xs') = ast xs 
            (y',xs'') = ast xs'
            in (Prod y y',xs'')
    | x == "+" = let 
            (y,xs') = ast xs
            (y',xs'') = ast xs'
            in (Sum y y',xs'')

您可以在let内拥有任意数量的定义,而不只是一个。

where语句在最后范围内,而let语句在in结束。这就是您收到错误消息的原因 - 它认为您仍然在where,但您想要继续。将您的where条款推迟到最后。

在这种情况下,您并不需要将它们分开,因此可以将它们合并到一个地方,但let通常对此问题很有用。