Haskell обратная польская запись - PullRequest
0 голосов
/ 01 декабря 2018

будучи новичком в 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 голосов
/ 01 декабря 2018

Вы правильно реализовали функцию, но ваш синтаксис немного неправильный - вы использовали охранники, когда хотите использовать сопоставление с образцом:

  • Используется сопоставление с образцом когда вы хотите разложить параметр на более мелкие части или обработать его в нескольких случаях;тогда как
  • 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 для чего-то вроде сообщения об ошибке.

РЕДАКТИРОВАТЬ: В комментариях ниже @Чепнер предложил другой способ сделать это, используя сопоставление с образцом и охранники:

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

Это еще раз иллюстрирует разницу между ними: сопоставление с образцом используется для разложения первого аргумента на x, y иys, в то время как охранники используются в логических условиях (при этом otherwise фактически определено в Prelude как True).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...