使用表达式树解析输入

Parsing Input Using Expression Tree

提问人:skiboy108 提问时间:12/13/2022 更新时间:12/14/2022 访问量:122

问:

因此,我尝试获取用户输入,然后将其解析为我为其设置了表达式树的表达式。我拥有的表达式树是:

data Expression = State [Float] Float 
                    | Const Float
                    | Plus Expression Expression
                    | Times Expression Expression
                    | Minus Expression Expression
                    | Divide Expression Expression
                    | Uminus Expression
                    deriving(Show, Read)

然后我尝试获取输入,然后使用以下两行对其进行解析。

expression <- getLine
read expression

在获取输入或使用 read 时,我是否缺少什么?它给我的错误是:

Main.hs:94:3: error:
    • No instance for (Read (IO a0)) arising from a use of ‘read’
    • In a stmt of a 'do' block: read expression
      In the expression:
        do putStrLn "Input an expression to evaluate"
           expression <- getLine
           read expression
           print ("Hello World")
           ....
      In an equation for ‘main’:
          main
            = do putStrLn "Input an expression to evaluate"
                 expression <- getLine
                 read expression
                 ....
解析 Haskell IO 表达式树

评论


答:

1赞 gltronred 12/13/2022 #1

如果你在 do-notation 中使用了一些东西,它就在 Monad 中(或者 Applicative,如果你打开一些语言编译指示)。

所以,你的代码

expression <- getLine
read expression

写在单子里。然后应该有一个类型,用于一些单子和一些类型。编译器可以从 的类型推断出 ,所以是 。read expressionm amamgetLine :: IO StringmIO

但有类型.因此,应该是 .但是没有 for 的实例,您不能将字符串转换为返回某些内容的 IO 操作。readread :: Read b => String -> bbIO aReadIO a

问题是你想执行纯计算。为此,您必须使用:let

expression <- getLine
let parsed = read expression :: Expression
print parsed

在这里,我用于将名称绑定到 的结果。然后你必须做一些 值 ,例如,你可以打印它。letparsedread expressionparsed

我必须指定类型,因为可以处理任何具有实例的东西,而编译器无法选择 .如果我写一些更具体的东西,比如 ,那么可以省略类型声明。printShowparsedperformOperation :: Expression -> IO ()

评论

0赞 skiboy108 12/14/2022
这奏效了,谢谢!除此之外,我唯一需要做的就是定义我希望它被解析为的类型。所以:
0赞 skiboy108 12/14/2022
let parsed = read expression :: 表达式
1赞 Daniel Wagner 12/14/2022
我宁愿,鉴于我们已经进入了,作为一个小习惯。 当事情出错时,在更好的时间抛出更好的异常。parsed <- readIO expressionIOreadIO
0赞 gltronred 12/14/2022
@skiboy108是的,我忘了。您必须添加类型,因为可以处理任何具有实例的内容,因此编译器在类型推理方面需要帮助。如果你做一些特定的事情而不是(比如),那么你可以省略类型printShowprintperformOperation :: Expression -> IO ()