2012-08-26 14 views
5

Próbuję ustawić schemat autoryzacji, w którym sprawdzam, czy 1. użytkownik jest zalogowany 2. użytkownik ma dostęp do określonego obiektu. W tym celu najpierw zadzwonię pod numer maybeAuthId, następnie spróbuję pobrać bieżący obiekt i "dołączyć" do innej tabeli, która zawiera uprawnienia. Istnieją dwa poziomy przypadków przypadkowych i jeden poziom listy pustych list. Myślałem o używaniu MaybeT, ale albo jestem zbyt zmęczony, żeby to zadziałało, albo "transformator typu niezupełnie monadowego" nie może być użyty z MaybeT. Czy istnieje dobry sposób na radzenie sobie z głębokimi maybami?Głęboki może stos z takodem

Edytuj:

Byłem trochę niejasny, jak się wydaje. Miałem na myśli, że mam coś takiego:

case foo of 
    Nothing -> something 
    Just foo' -> do 
     bar <- somethingelse 
     case bar of 
     Nothing -> ... 
     Just bar' -> ... 

Odpowiedz

6

Możesz całkowicie użyć MaybeT dla Yesod. Zrób to tak:

runMaybeT $ do 
    uid <- MaybeT maybeAuthID 
    car <- MaybeT . runDB . getBy $ UniqueCarOwner uid 
    location <- MaybeT . liftIO . ciaLocateLicensePlate . licensePlate $ car 
    country <- MaybeT . findCountry $ location 
    return (car, country) 

Jak już powiedziałeś, większość funkcji nie jest zoptymalizowanych pod kątem obsługi błędów ogólnych w Yesod. Jeśli jednak masz coś w postaci Monad m => m (Maybe a), możesz po prostu użyć MaybeT, aby zamienić go na Monad m => Maybe (m a).

+0

Dzięki. Minęło trochę czasu, odkąd użyłem transformatorów i zapomniałem, że muszę je zawinąć w MaybeT. – Masse

1

To nie jest do końca jasne, co masz na myśli przez „Handle głębokich maybes”, ale można użyć monadycznego join (od Control.Monad), aby usunąć jeden poziom zagnieżdżenia naraz.

ghci> :m +Control.Monad 
ghci> join (Just (Just 3)) 
Just 3 
ghci> join (Just Nothing) 
Nothing 
ghci> join Nothing 
Nothing 

Używanie MaybeT jest prawdopodobnie lepszym rozwiązaniem dla twojego problemu. Jeśli wyjaśnisz, co próbujesz zrobić, możemy pomóc Ci sformułować to za pomocą metody MaybeT.

2

Z tego co rozumiem, twoje warstwy wyglądać następująco:

Maybe [Maybe r] 

... i chcesz join dwa Maybe y razem, ale lista jest w drodze. To jest właśnie problem sequence rozwiązuje:

sequence :: (Monad m) => [m r] -> m [r] 

Zauważ, że jeśli specjalizujemy sequence do Maybe monady otrzymujemy:

sequence :: [Maybe r] -> Maybe [r] 

W tym konkretnym przypadku, sequence zwróci Nothing jeśli istnieje co najmniej jeden Nothing na liście, ale jeśli wszystkie są Just s, to połączy je wszystkie w jeden Just.

Pozostaje mapować sequence nad zewnętrznym Maybe:

fmap sequence :: Maybe [Maybe r] -> Maybe (Maybe [r]) 

Teraz to jest dokładnie w postaci musimy do przyłączenia:

join . fmap sequence :: Maybe [Maybe r] -> Maybe [r] 

tak, to intuicyjnie, co do powyższej funkcji to znaczy, że jeśli wszystkie wewnętrzne wewnętrzne i zewnętrzne Maybe jest Just, to łączy ono cały wynik w pojedynczym Just zawierającym lista. Jeśli jednak dowolny Maybe (wewnętrzny lub zewnętrzny) to Nothing, ostateczny wynik to Nothing.

Zauważ, że pomimo robienia gonitwy w ciemno, otrzymaliśmy funkcję, która intuicyjnie robi to, co należy. Jest to siła abstrakcji zakorzeniona w teorii kategorii.