Применение функции, которая может не работать со всеми значениями в списке - PullRequest
3 голосов
/ 07 апреля 2010

Я хочу применить функцию f к списку значений, однако функция f может случайно произойти сбой (в действительности она вызывает сервис в облаке).

Я подумал, что хотел бы использовать что-то вроде map, но я хочу применить функцию ко всем элементам в списке, а затем я хочу знать, какие из них были неудачными, а какие - успешными.

В настоящее время я обертываю объекты ответа функции f парой ошибок, которую затем я мог бы эффективно unzip впоследствии

, то есть что-то вроде

g : (a->b) -> a -> [ b, errorBoolean]

f : a-> b

и затем запустить код ... map g (xs)

Есть ли лучший способ сделать это?Другой альтернативный подход состоял в том, чтобы перебрать значения в массиве, а затем вернуть пару массивов, один из которых содержал список успешных значений, а другой - список ошибок.Мне кажется, это должно быть довольно распространенным явлением.В качестве альтернативы я мог бы вернуть какое-то специальное значение.Как лучше всего справляться с этим ??

Ответы [ 2 ]

15 голосов
/ 07 апреля 2010

Если f обращается к облаку, то f, несомненно, использует некоторую монаду, вероятно, монаду IO или монаду, полученную из монады IO. Существуют монадические версии map. Вот что вы обычно делаете в качестве первой попытки:

f :: A -> IO B -- defined elsewhere
g :: [A] -> IO [B]
g xs = mapM f xs
-- or, in points-free style:
g = mapM f

Имеет (возможно) нежелательное свойство, что g не будет выполнен, не возвращая значений, если какой-либо вызов f не удастся. Мы исправим это, сделав так, чтобы f возвращал либо ответ, либо сообщение об ошибке.

type Error = String
f :: A -> IO (Either Error B)
g :: [A] -> IO [Either Error B]
g = mapM f

Если вы хотите, чтобы все ошибки возвращались вместе, а все успехи объединялись вместе, вы можете использовать функции lefts и rights из Data.Either.

h :: [A] -> IO ([B], [Error])
h xs = do ys <- g xs
          return (rights ys, lefts ys)

Если вам не нужны сообщения об ошибках, просто используйте Maybe B вместо Either Error B.

Тип данных Either является наиболее распространенным способом представления значения, которое может привести либо к ошибке, либо к правильному значению. Ошибки используют конструктор Left, правильные значения - конструктор Right. В качестве бонуса «право» также означает «правильный» на английском языке, но причина, по которой правильное значение использует конструктор Right, на самом деле глубже (потому что это означает, что мы можем создать функтор типа Either, который изменяет правильные результаты что невозможно по конструктору Left).

2 голосов
/ 07 апреля 2010

Вы можете написать свой g, чтобы вернуть Возможно, монаду :

f: a -> b
g: (a -> b) -> a -> Maybe b

Если f не удастся, g вернет Nothing, в противном случае он вернет Just (f x).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...