haskell反向波兰表示法

时间:2018-11-30 22:40:11

标签: haskell functional-programming postfix-notation

haskell的新手,我决定尝试实现一个迷你反向抛光符号功能:

采用list类型的int和字符串运算符('*','+','/','-'

将运算符应用于tail元素和tail-1元素

返回结果list,并弹出操作中涉及的两个元素,并将结果元素附加到尾部,如下所示:

Where e0 = original element at index 0

r = result of the operation:

result = [e0,e1,e2...r] (elements popped off: eN, eN-1)

这是我到目前为止的代码:

import Data.List
import System.IO

step :: [Int] -> String -> [Int]
step stack operator
    | (x:y:ys) "*" = (x * y):ys
    | (x:y:ys) "+" = (x + y):ys
    | (x:y:ys) "-" = (x - y):ys
    | (x:y:ys) "/" = (x / y):ys

它给了我以下编译错误:

• Couldn't match expected type ‘[Char] -> Bool’
                  with actual type ‘[a3]’
    • The function ‘x : y : ys’ is applied to one argument,
      but its type ‘[a3]’ has none
      In the expression: (x : y : ys) "/"
      In a stmt of a pattern guard for
                     an equation for ‘step’:
        (x : y : ys) "/"

我相信这是我语法错误的结果, 欢迎任何帮助!

1 个答案:

答案 0 :(得分:3)

您已经正确实现了该功能,但是语法略有错误-当您要使用模式匹配时使用了防护措施:

  • 模式匹配用于要将参数分解为较小的部分或在某些情况下进行处理的情况;而
  • Guards 用于基于布尔条件选择函数的一个分支,类似于if / then / else表达式。 (因此,警卫的条件必须为Bool类型的有效表达式。)

在您的代码中,您使用过防护,但是您确实想要模式匹配,如下所示:

step :: [Int] -> String -> [Int]
step (x:y:ys) "*" = (x * y):ys
step (x:y:ys) "+" = (x + y):ys
step (x:y:ys) "-" = (x - y):ys
step (x:y:ys) "/" = (x / y):ys

但是,这仍然会产生错误:

* No instance for (Fractional Int) arising from a use of `/'
* In the first argument of `(:)', namely `(x / y)'
  In the expression: (x / y) : ys
  In an equation for `step': step (x : y : ys) "/" = (x / y) : ys

这个错误非常清楚:您正在尝试/一个整数,但是整数不是Fractional,所以您不能这样做。如果要整数除法,可以将其替换为div x y,否则可以在类型签名中将Int更改为Float,以允许使用非整数值。

但是,即使进行了此更改,仍然存在一个细微的错误:如果列表中的元素少于两个,或者使用了不受支持的运算符,该怎么办?正确的做法是使用step _ _ = (something)在结尾进行模式匹配,其中_是一种特殊的语法,可以匹配所有内容。 (或者,如果您想参考step stack operator = (something)stack来获取类似错误消息之类的信息,也可以使用operator

编辑:在下面的评论中,@ chepner建议了另一种使用模式匹配和防护的方法:

step :: [Int] -> String -> [Int]
step (x:y:ys) op
    | op == "*" = (x * y):ys
    | op == "+" = (x + y):ys
    -- etc.
    | otherwise = (some error case)

这再次说明了两者之间的区别:模式匹配用于将第一个参数分解为xyys,而后卫用于布尔条件(与{ {1}}实际上在前奏中定义为等于otherwise)。