2014-09-28 5 views
2

Еще раз, через плохое, плохое программирование, мне удалось попасть в ужасную ситуацию с типами.Преобразование Либо (IO b) в IO (либо a)

Можно ли каким-либо образом преобразовать Either a (IO b) в IO (Either a b)? Я знаю, что это не очень хорошее программирование, чтобы попасть в эту ситуацию, поэтому я также буду открыт для предложений о том, как избежать подобных ситуаций.

+6

Почему бы тебе не показать нам, как вы [продолжать получать] (http://stackoverflow.com/questions/26051376/how-to-print-the-type-either-string-io-string) в этой ситуации, и, возможно, мы можем показать вам, как этого избежать. – AndrewC

ответ

5

Несомненно!

convert :: Either a (IO b) -> IO (Either a b) 
convert = either (return . Left) (fmap Right) 

Теперь, если вы хотите, чтобы преобразовать IO (Either a b) в Either a (IO b), вы бы в беде, но вы этого не сделаете, так что ты в порядке.

Давайте посмотрим, как convert работы:

  • either :: (a -> c) -> (b -> c) -> Either a b -> c, поэтому он берет на себя шаблон для нас, выяснить, есть ли у нас в a или IO b в вашем случае.
  • если у нас есть a, нам просто нужно его преобразовать в IO (Either a b). Конструктор Left :: a -> Either a b делает первую часть, а IO является монадой, поэтому мы можем использовать return, чтобы сделать Either a b -> IO (Either a b).
  • если у нас есть IO b, мы должны преобразовать его в IO (Either a b). Мы могли бы сделать это с делать обозначения:

    given iob = do 
        b <- iob 
        return . Right $ b 
    

    с использованием return . Right в b -> IO (Either a b). Но это именно та ситуация, в которой mapM :: Monad m => (a -> b) -> m a -> m b для Монадов: given iob = mapM Right iob. Большинство людей не используют mapM, хотя, поскольку это только специализация fmap в Monads, поэтому мы будем использовать fmap: given iob = fmap Right iob, или, pointfree: given = fmap Right.

+12

'' convert'' вот на самом деле частный случай '' sequenceA'', экспортируемый из '' Data.Traversable''. –

+1

Хорошая точка. При использовании 'liftM' вместо' fmap' это будет особый случай 'Data.Traversable.sequence';) –

+0

Обратите внимание, что тип ограничен без уважительной причины. Это работает для любой монады вместо IO. – Ingo

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