1

我正在为我们得到的一项任务而苦苦挣扎。我在这里根据不同的指南稍微编写了这段代码:不在范围内:数据构造函数

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

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

这个问题似乎与在“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'

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

完整代码:

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'
4

2 回答 2

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是函数定义中的每个方程只能有一个子句。因此,wherex == "*"替代方案之后,解析器期望模式的等式(x:xs)是完整的。

只需删除有问题的where,该where子句的范围涵盖等式中的所有替代项,并且两个where子句具有相同的内容(并且缩进更好,where根据我的喜好,属于自己的行)。由于let在第一个替代方案中使用了也存在于where子句中的绑定,因此也可以将其删除:

ast [] = error "Empty string"
ast (x:xs) | all isDigit x = (Leaf (read x),xs)
    | x == "-" = (Min y,xs')
    | x == "*" = (Prod y y',xs'')
    | x == "+" = (Sum y y',xs'')
      where
        (y,xs') = ast xs
        (y',xs'') = ast xs'
于 2012-10-05T14:48:09.560 回答
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'')

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

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

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

于 2012-10-05T14:51:49.490 回答