Обработка на грешки и монади?

Опитвам се да разбера как да приложа Maybe-идиома от Haskel.. Чета http://en.wikibooks.org/wiki/Haskell/Understanding_monads/Maybe, което показва, че търсене в речник може да върне Maybe и че тази стойност се разпространява чрез оператора >>=.

Примерът от URL адреса:

Ако след това искаме да използваме резултата от търсенето в правителствената база данни при трето търсене (да речем, че искаме да потърсим техния регистрационен номер, за да видим дали дължат данък върху автомобила), тогава бихме могли да разширим нашата функция getRegistrationNumber:

getTaxOwed :: String       -- their name
           -> Maybe Double -- the amount of tax they owe
getTaxOwed name = 
  lookup name phonebook >>=
    (\number -> lookup number governmentalDatabase) >>=
      (\registration -> lookup registration taxDatabase)

Или, използвайки стила do-block:

getTaxOwed name = do
  number       <- lookup name phonebook
  registration <- lookup number governmentalDatabase
  lookup registration taxDatabase

Въпрос:

Как да се справя с обработката на грешки? Мисля, че повечето кодове ще имат полза от това да кажат къде нещата са се объркали. Вместо просто да докладва „не можах да намеря John Doe нито в телефонния указател, нито в правителствената база данни“, трябва да докладва кой ресурс е имал проблеми.


person Carlo V. Dango    schedule 13.08.2012    source източник
comment
Това, което открихте е, че Може би е най-полезно, ако има само един възможен случай на неуспех, помислете за корен квадратен от отрицателно число. От друга страна, можете просто да направите sqrt :: Either Complex Double   -  person Sarah    schedule 13.08.2012
comment
Да, прав си. ето общо решение за проблема hackage.haskell.org/packages/archive/transformers/0.3.0.0/doc/ . Може би не става въпрос за точното обработване на грешки   -  person permeakra    schedule 13.08.2012


Отговори (2)


Можете да използвате екземпляра на монадата за Either String, който по същество е дефиниран като

instance Monad (Either String) where                                             
  fail msg = Left msg                                                            
  return x = Right x                                                             

  Left msg >>= k = Left msg                                                      
  Right x  >>= k = k x

(Истинската дефиниция е малко по-намесена.)

Ако след това дефинираме речниците като двойки, състоящи се от етикет и справочна таблица

type Dict a b = (String, [(a, b)])

phonebook' :: Dict String Int
phonebook' = ("phone book", phonebook)

governmentalDatabase' :: Dict Int Int
governmentalDatabase' = ("governmental database", governmentalDatabase)

taxDatabase' :: Dict Int Double
taxDatabase' = ("tax database", taxDatabase)

където phonebook, governmentalDatabase и taxDatabase са както ги дефинирахте преди, можем да използваме алтернативна монадична функция за търсене, която връща резултата си в Either String-монада:

lookup' :: (Eq a, Show a) => a -> Dict a b -> Either String b
lookup' key (descr, table) = case lookup key table of
  Nothing  -> Left ("couldn't find " ++ show key ++ " in " ++ descr)
  Just val -> Right val

Илюстрирайки силата на монадите, единственото нещо, което сега трябва да се промени във вашата клиентска функция, е сигнатурата на типа:

getTaxOwed :: String               -- their name                                 
           -> Either String Double -- either an error message                    
                                   -- or the amount of tax they owe              
getTaxOwed name = do
  number       <- lookup' name phonebook'
  registration <- lookup' number governmentalDatabase'
  lookup' registration taxDatabase'

Изпълнението на тази функция на неизвестно име дава:

> getTaxOwed "Joe"
Left "couldn't find \"Joe\" in phone book"
person Stefan Holdermans    schedule 13.08.2012

Типът данни Може би има само стойността "Нищо" за сигнализиране на грешка. Ако искате да върнете конкретно съобщение за грешка, предлагам тип данни „Either“, който може да върне стойност „Left a“ или „Right a“. Прочетете повече за това как да използвате това на http://learnyouahaskell.com/for-a-few-monads-more#error

person tauli    schedule 13.08.2012