«последовательность», похоже, работает неправильно с «Либо`

#haskell

#хаскелл

Вопрос:

Когда я использую sequence on Maybe , кажется, все работает нормально:

 sequence [Just 2, Just 3] == Just [2, 3]
sequence [Just 2, Just 3, Nothing] == Nothing
 

Тип результата соответствует sequence типу: (Traversable t, Monad m) => t (m a) -> m (t a) , m (t a) становится Maybe [Int] , и это тоже правильно Nothing .

Однако, если я сделаю что-то подобное:

 sequence [Right 2, Right 3] == Right [2, 3]
sequence [Right 2, Right 3, Left 4] == Left 4
 

Как Left 4 тип m (t a) ? Если Right [2, 3] есть Either [Int] , то Left 4 также следует использовать этот тип, но, очевидно (для меня), это не так. Чего мне не хватает?

Комментарии:

1. Left похоже Nothing на a Maybe .

2. Да, но он не нулевой, он принимает аргумент, и этот аргумент должен иметь тип, тот же тип Right , который принимает, насколько я понимаю.

3. m здесь Either b , нет Either .

Ответ №1:

Давайте сначала проведем анализ типов. m Нет Either , m есть m ~ Either b . Действительно, поскольку m принимает параметр одного типа.

Итак, если мы установим m ~ Either b , то получим:

 (Traversable t) => t (Either b a) -> Either b (t a) 

и t ~ [] таким образом, мы получаем:

 [Either b a] -> Either b [a] 

Вы можете видеть Either b , как более сложная версия Maybe where Left e используется для отображения ошибки (вычисления, которые завершились неудачно) с e объектом error (это может быть, например, строка или какой-либо другой тип), и Right x вычисления, которые завершились успешно с x результатом. Таким образом, в этом случае sequence будет проверяться, удалось ли выполнить список вычислений, и если это так, он вернет a Right [x1, x2, …, xn] , и если одно из вычислений завершилось неудачно, оно вернет первый «объект ошибки».

Это основано на экземпляре Monad (Either b) , действительно [src]:

 -- | @since 4.4.0.0
instance Monad (Either e) where
    Left  l >>= _ = Left l
    Right r >>= k = k r
 

Таким образом, для a Left l он вернет a Left l , тогда как для a Right он будет применяться k к результату r .