Вы находитесь на правильном пути; давайте посмотрим на некоторые изменения в вашем коде, которые я бы предложил.
Ваша add1
функция довольно близка, но у вас есть две небольшие проблемы - первая - это соответствие шаблону, которое вы предоставляете: чтобы быть синтаксически правильным, вам нужно, чтобы все совпадение было в скобках. Второй - второй минус (двоеточие). тип cons имеет тип a -> [a] -> [a]
, поэтому он отлично работает с (x+y)
в качестве первого параметра; однако, поскольку xs
уже имеет тип [Int]
, вам не нужно указывать : []
.
add1 (x:y:xs) = (x+y) : xs
Далее, поскольку вы имеете дело с Int
s и списками Int
s, использование некоторого типа a
не имеет смысла в этом контексте.
push :: [Int] -> Int -> [Int]
Наконец, ваша рабочая лошадка. Из-за отсутствия конструкций циклов в Haskell способ сделать цикл пользовательского ввода (также известный как REPL ) - через рекурсию. Из-за этого имеет смысл принять параметр. Давайте сделаем это вашим [Int]
стеком. Функция для чтения одной строки из stdin в виде строки - getLine
, которая имеет тип IO String
. Наконец, вы действительно должны обработать этот ввод. Для простоты я только что включил эту логику в оператор case
в xcl
, но это также можно было бы сделать с помощью dispatch
или аналогичной функции (на самом деле, если ваш RPN-калькулятор становится более сложным, это будет иметь свои достоинства). Действие для каждого случая должно повторяться в вашем цикле xcl с измененным стеком. Когда вы выходите, он должен просто выйти - что является хорошим использованием return
.
xcl :: [Int] -> IO ()
xcl st = do
print st
answer <- getLine
case answer of
"q" -> return ()
"c" -> xcl ([] ::[Int])
"+" -> xcl $ add1 st
x -> xcl $ push st $ read x
Фактически, вы могли бы сделать еще один шаг и защитить себя от исключений - что произойдет, когда пользователь передаст какую-то не функциональную, не числовую строку? Приведенный выше код завершится ошибкой, за исключением «без разбора». Лучший способ обойти это - использовать reads
вместо read
, как обсуждается в этого ответа . reads
возвращает либо список с одной записью - кортеж, содержащий проанализированный номер и оставшуюся строку, либо пустой список (указывающий на неудачное чтение). Например:
x -> case (reads x) of
[(num,_)] -> xcl $ push st num
_ -> xcl st