Проблемы с Haskell в реализации RPN caculator
Я пытаюсь внедрить RPN caculator в Haskell. Это упражнение от Learn You a Haskell. Вот мой код:
import Data.List
solveRPN :: String -> Int
solveRPN str = head $ foldl putStack [] (words str)
where putStack accumulator token
| token == "+" = pFunction (+)
| token == "-" = pFunction (-)
| token == "*" = pFunction (*)
| token == "/" = pFunction (`div`)
| otherwise = accumulator ++ [read token :: Float]
where pFunction function = (int $ init accumulator) ++ [function argu1 argu2]
argu1 = last accumulator
argu2 = last $ init accumulator
Функция solveRPN
сначала разбейте строку на токены. (Например:"4 3 2 + *"
->["4","3","2","+","*"]
) Затем один за другим токены помещаются в стек. Если он встречает оператор, последние два элемента в стеке обрабатываются оператором, а полученное значение затем помещается обратно в стек. Когда весь список пройден, в стеке остается только один элемент, и это ответ.
Здесь есть некоторые проблемы:
В
(int $ init accumulator)
Я хочу отменить последние два элемента в стеке. Есть ли альтернатива(int $ init accumulator)
?Код не может пройти компиляцию. GHC сказал "ошибка разбора на входе ("
на этой линии:| token == "/" = pFunction (
ДИВ)
, Я подозреваю, что проблема может исходить отpFunction
, Его параметр является оператором (или я могу назвать это функцией?), И я не уверен, является ли "функция как параметр функции" допустимой в Haskell. Это законно? Есть ли альтернатива?Я провел несколько экспериментов в GHCi и обнаружил нечто странное:
Prelude> let plus = (+) Prelude> :t (+) (+) :: Num a => a -> a -> a Prelude> :t plus plus :: Integer -> Integer -> Integer
Почему тип плюса отличается от типа (+)?
Спасибо за ваше внимание и терпение. (:
2 ответа
В
(int $ init accumulator)
Ты имел ввиду init $ init accumulator
? При этом, вы можете написать свой собственный dropLast2
функция, которая делает то же самое, что и init . init
но обходит список только один раз, что-то вроде
dropLast2 :: [a] -> [a]
dropLast2 [] = []
dropLast2 [_] = []
dropLast2 [_,_] = []
dropLast2 (x:xs) = x : dropLast2 xs
Код не может пройти компиляцию.
| token == "/" = pFunction (`div`)
Вы используете backticks (`) для использования функций с двумя аргументами в качестве инфиксных функций. Тем не менее, используя круглые скобки вокруг div
вы пытаетесь отменить его сразу, что немного отключено и является ошибкой парсера. Просто использовать
| token == "/" = pFunction div
вместо. Тем не менее, есть одна важная вещь. div
тип
div :: Integral a => a -> a -> a
Тем не менее, ваш аккумулятор является списком Float
, div
не может работать на тех. Тем не мение, Float
является примером Fractional
класс, так что вы можете просто использовать (/)
:
(/) :: Fractional a => a -> a -> a
и, следовательно, получить
| token == "/" = pFunction (/)
Я провел несколько экспериментов в GHCi и нашел что-то странное
(+)
является частью Num
учебный класс. Ваш plus
не является частью какой-либо функции, и GHC пытается определить ее тип. И тогда наступает ограничение мономорфизма. См. Ошибка типа при написании функции max для получения дополнительной информации.
По поводу вашего первого вопроса:
У меня создается впечатление, что вы используете списки неправильно. Если вы помещаете элемент в стек, вы должны добавить его к списку, используя :
оператор. Появление двух верхних элементов становится drop 2 stack
что гораздо приятнее, я думаю.
Делать это таким образом также было бы более эффективным, так как :
это операция с постоянным временем, а ++
является линейным по размеру первого аргумента (т.е. размер вашего стека).