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