Стандартная функция Haskell:: (a → Возможно, b) → [a] → Может быть, b

Существует стандартная функция tryPick, если F #, которая возвращает первое (слева направо, если вообще) успешное применение функции на элементе список. Я прыгаю, есть такая стандартная функция, как в Haskell. я попробовал Hoogle и ничего не нашел.

Я новичок в Haskell, и я не уверен, какой правильный способ это сделать. Вы сделали бы это так:

tryPick:: (a -> Maybe b) -> [a] -> Maybe b
tryPick try xs = case Maybe.mapMaybe try xs of
    [] -> Nothing
    (x:_) -> Just x

?

Ответ 1

Функция listToMaybe в Data.Maybe выглядит довольно хорошо:

tryPick f = listToMaybe . mapMaybe f

Ответ 2

Вы хотите:

tryPick :: (a -> Maybe b) -> [a] -> Maybe b
tryPick f as = msum (map f as)

Я объясню, как это работает.

map f as создает список возможных действий Maybe, чтобы попробовать:

map f as :: [Maybe b]

msum последовательно пытается выполнить их до тех пор, пока не будет выполнено одно успешное выполнение (возврат значения как Just), или все они откажутся (вернув Nothing). Например:

> msum [Nothing, Just 2, Just 3, Nothing]
Just 2
> msum [Nothing, Nothing]
Nothing

Обратите внимание, что тип msum более общий, поэтому мы можем обобщить подпись на:

tryPick :: (MonadPlus m) => (a -> m b) -> [a] -> m b

Теперь это будет работать для любого MonadPlus. Получайте удовольствие, узнав, что он делает для других типов MonadPlus.

Ответ 3

Это не обязательно самое простое решение, но я считаю важным подчеркнуть решение First Monoid. Я думаю, что это самый красивый.

import Data.Monoid
import Data.Foldable (Foldable, foldMap)

tryPick :: (a -> Maybe b) -> [a] -> Maybe b
tryPick f = getFirst . foldMap (First . f)     -- this is just `foldMap f`
                                               -- with the "firsty" Maybe Monoid

Это также немедленно обобщается на любой Foldable с точно таким же кодом

tryPick :: Foldable t => (a -> Maybe b) -> t a -> Maybe b

Foldable экземпляры предоставляют способы "разбить" все элементы вместе, используя Monoid s. First Monoid, определяемый как

newtype First a = First { getFirst :: Maybe a }

является специализацией Maybe с операцией mappend, которая выбирает "первый" или "самый левый" Just.

Итак, объединяя их, getFirst . foldMap (First . f) вычисляет вашу функцию (a -> Maybe b) по всем a в [a], а затем разбивает результаты вместе с правилом, победителем которого является "первый" Just.

Ответ 4

Я немного опаздываю на вечеринку, но здесь вариант ответа Дж. Абрахамсона, который использует прекрасную функцию ala' Конор Макбрайд из newtype пакет:

import Control.Newtype (ala')
import Data.Foldable (Foldable, foldMap)
import Data.Monoid (First(..))

tryPick :: (Foldable t) => (a -> Maybe b) -> t a -> Maybe b
tryPick = ala' First foldMap

Это может показаться немного загадочным, но я нахожу, как он отделяет "сборный сосуд" (First) от "схемы сбора" (foldMap) и как от "функции предварительной обработки" (a -> Maybe b) - все, скрывая newtype упаковку и разворачивание - довольно красиво. ala был в моем опыте прекрасным инструментом для создания красивого кода, и я бы хотел его подключить. Спасибо, Конор!