Первые три случая – такие же, как и прежние, только новый стек обёрнут в конструктор >Just
(для этого мы использовали здесь функцию >return
, но могли и просто написать >Just
). В последнем случае мы используем вызов >readMaybe numberString
, а затем отображаем это с помощью >(:xs)
. Поэтому если стек равен >[1.0,2.0]
, а выражение >readMaybe numberString
даёт в результате >Just
>3.0
, то результатом будет >[3.0,1.0,2.0]
. Если же >readMaybe numberString
даёт в результате значение >Nothing
, результатом будет >Nothing
.
Давайте проверим функцию свёртки отдельно:
>ghci> foldingFunction [3,2] "*"
>Just [6.0]
>ghci> foldingFunction [3,2] "-"
>Just [-1.0]
>ghci> foldingFunction [] "*"
>Nothing
>ghci> foldingFunction [] "1"
>Just [1.0]
>ghci> foldingFunction [] "1 уа-уа-уа-уа"
>Nothing
Похоже, она работает! А теперь пришла пора для новой и улучшенной функции >solveRPN
. Вот она перед вами, дамы и господа!
>import Data.List
>solveRPN :: String –> Maybe Double
>solveRPN st = do
> [result] <– foldM foldingFunction [] (words st)
> return result
Как и в предыдущей версии, мы берём строку и превращаем её в список слов. Затем производим свёртку, начиная с пустого стека, но вместо выполнения обычной свёртки с помощью функции >foldl
используем функцию >foldM
. Результатом этой свёртки с помощью функции >foldM
должно быть значение типа >Maybe
, содержащее список (то есть наш окончательный стек), и в этом списке должно быть только одно значение. Мы используем выражение >do
, чтобы взять это значение, и называем его >result
. В случае если функция >foldM
возвращает значение >Nothing
, всё будет равно >Nothing
, потому что так устроена монада >Maybe
. Обратите внимание на то, что мы производим сопоставление с образцом в выражении >do
, поэтому если список содержит более одного значения либо ни одного, сопоставление с образцом окончится неудачно и будет произведено значение >Nothing
. В последней строке мы просто вызываем выражение >return result
, чтобы представить результат вычисления выражения в обратной польской записи как результат окончательного значения типа >Maybe
.
Давайте попробуем:
>ghci> solveRPN "1 2 * 4 +"
>Just 6.0
>ghci> solveRPN "1 2 * 4 + 5 *"
>Just 30.0
>ghci> solveRPN "1 2 * 4"
>Nothing
>ghci> solveRPN "1 8 трам-тарарам"
>Nothing
Первая неудача возникает из-за того, что окончательный стек не является списком, содержащим один элемент: в выражении >do
сопоставление с образцом терпит фиаско. Вторая неудача возникает потому, что функция >readMaybe
возвращает значение >Nothing
.