2016-06-13 3 views
3

У меня есть код, структурированный как пример ниже. Я почти уверен, что должен быть способ структурировать его гораздо более безопасным. Я бы предположил, что может помочь Монах (или Ошибка), но я не знаю, с чего начать. Любые указатели, чтобы заставить меня двигаться в правильном направлении?Как избежать пирамиды случаев?

data Data1 = Data1 { d2Id :: String } 
data Data2 = Data2 { d3Id :: String } 
data Data3 = Data3 { d4Id :: String } 

getData1 :: String -> IO (Either String Data1) 
getData2 :: String -> IO (Either String Data2) 
getData3 :: String -> IO (Either String Data3) 

process :: Data1 -> Data2 -> Data3 -> IO() 

get :: String -> IO() 
get id = do 
    r1 <- getData1 id 
    case r1 of 
    Left err -> print err 
    Right d1 -> do 
     r2 <- getData2 $ d2Id d1 
     case r2 of 
     Left err -> print err 
     Right d2 -> do 
      r3 <- getData3 $ d3Id d2 
      case r3 of 
      Left err -> print err 
      Right d3 -> do 
       process d1 d2 d3 

ответ

3

Я повторное открытие на этот вопрос, потому что я думаю, что было бы полезно, чтобы увидеть как превратить этот вид конкретного кода.

Нам понадобится несколько импорта:

import Control.Monad.Trans 
import Control.Monad.Trans.Either 

Затем превратить вашу get функции, применяя EitherT к каждому IO-действию, которое сигнализирует об ошибке, возвращая Either:

-- get' :: EitherT String IO() 
get' id = do 
    d1 <- EitherT $ getData1 id 
    d2 <- EitherT $ getData2 (d2Id d1) 
    d3 <- EitherT $ getData3 (d3Id d2) 
    liftIO $ process d1 d2 d3 

Обратите внимание, что мы не используем EitherT для process. Вместо этого мы используем liftIO, так как process не сигнализирует об ошибке.

GHC должен иметь возможность заключить типовую подпись, поэтому вам не нужно ее предоставлять.

Чтобы запустить новую версию, используйте runEitherT, которая будет возвращать Either значение в IO-монаду:

doit :: String -> IO() 
doit id = do 
    res <- runEitherT (get' id) 
    case res of 
    Left err -> print err 
    Right d -> return() 
+0

Почему вопрос закрыт? – Michael

+0

Это было отмечено как дуплекс. Этот вопрос возник раньше, но не совсем в этом контексте, поэтому я решил повторно открыть его и добавить ответ. – ErikR

Смежные вопросы