Изучай Haskell во имя добра! (Липовача) - страница 272

Вот это было основным телом нашей функции:

>import Data.List


>solveRPN :: String –> Double

>solveRPN = head . foldl foldingFunction [] . words

Мы превратили выражение в список строк и свернули его, используя нашу функцию свёртки. Затем, когда у нас в стеке остался лишь один элемент, мы вернули этот элемент в качестве ответа. Вот такой была функция свёртки:

>foldingFunction :: [Double] –> String –> [Double]

>foldingFunction (x:y:ys) "*" = (y * x):ys

>foldingFunction (x:y:ys) "+" = (y + x):ys

>foldingFunction (x:y:ys) "-" = (y - x):ys

>foldingFunction xs numberString = read numberString:xs

Аккумулятором свёртки был стек, который мы представили списком значений типа >Double. Если по мере того, как функция проходила по выражению в обратной польской записи, текущий элемент являлся оператором, она снимала два элемента с верхушки стека, применяла между ними оператор, а затем помещала результат обратно в стек. Если текущий элемент являлся строкой, представляющей число, она преобразовывала эту строку в фактическое число и возвращала новый стек, который был как прежний, только с этим числом, протолкнутым на верхушку.

Давайте сначала сделаем так, чтобы наша функция свёртки допускала мягкое окончание с неудачей. Её тип изменится с того, каким он является сейчас, на следующий:

>foldingFunction :: [Double] –> String –> Maybe [Double]

Поэтому она либо вернёт новый стек в конструкторе >Just, либо потерпит неудачу, вернув значение >Nothing.

Функция >reads похожа на функцию >read, за исключением того, что она возвращает список с одним элементом в случае успешного чтения. Если ей не удалось что-либо прочитать, она возвращает пустой список. Помимо прочитанного ею значения она также возвращает ту часть строки, которую она не потребила. Мы сейчас скажем, что она должна потребить все входные данные для работы, и превратим её для удобства в функцию >readMaybe. Вот она:

>readMaybe :: (Read a) => String –> Maybe a

>readMaybe st = case reads st of [(x, "")] –> Just x

>                                _ –> Nothing

Теперь протестируем её:

>ghci> readMaybe "1" :: Maybe Int

>Just 1

>ghci> readMaybe "ИДИ К ЧЁРТУ" :: Maybe Int

>Nothing

Хорошо, кажется, работает. Итак, давайте превратим нашу функцию свёртки в монадическую функцию, которая может завершаться неудачей:

>foldingFunction :: [Double] –> String –> Maybe [Double]

>foldingFunction (x:y:ys) "*" = return ((y * x):ys)

>foldingFunction (x:y:ys) "+" = return ((y + x):ys)

>foldingFunction (x:y:ys) "-" = return ((y - x):ys)

>foldingFunction xs numberString = liftM (:xs) (readMaybe numberString)