2016-08-29 5 views
6

Я только что сам пишу этот код:В Haskell есть абстракция для <?> -оператора?

import Control.Applicative ((<|>)) 

x = mA <|> mB <?> c 

(<?>) :: Maybe a -> a -> a 
Just x <?> _ = x 
Nothing <?> y = y 

Где mA :: Maybe a, mB :: Maybe a, c :: a и x :: a. В основном, код говорит: выберите первый вариант, который не empty, и по умолчанию c. Вы можете назвать это «reverse Maybe monad», где аналогия с <?> будет pure.

Эквивалентно, я мог бы написать

Just x = mA <|> mB <|> pure c, 

, но я чувствую себя некомфортно с неопровержимым рисунком. Или, конечно,

x = fromMaybe c (mA <|> mB) 

т.к. fromMaybe === flip <?>.

Оператор <?> вдохновлен парсеком. Я всегда становлюсь подозрительным, когда обнаруживаю, что я определяю такие функции полезности, как это, но я не мог найти это поведение по умолчанию.

По-видимому, Alternative и Applicative недостаточно сильны.

Я пропустил тип-класс?

+0

FWIW: '' '' parsec' дает читателю понятное для парсера имя. В любом случае это не влияет на фактический синтаксический анализ. – phadej

+0

Итак, действительно '() = flip fromMaybe'? Похоже, стандартная библиотека предоставляет то, что вы хотите, просто не совсем в том виде, в котором вы хотели бы быть. Также, конечно, это не часть «Аппликативной» или «Альтернативы», потому что как это работает для других экземпляров, например списков? –

+0

@phadej Вы правы. В parsec '' не подразумевает дефолт. Поэтому моя аналогия слаба. –

ответ

8

Я думаю, что это хорошая идея оставить вещи на (<?>) = flip fromMaybe.

Если вы хотите обобщить, хотя, Foldable, кажется, самый простой класс с понятием пустоты:

(<?>) :: Foldable t => t a -> a -> a 
ta <?> a = foldr const a ta 

Это возвращает a если ta пуст или иначе первый элемент ta. Примеры:

Just 0 <?> 10 == 0 
Nothing <?> 0 == 0 
[] <?> 10 == 10 
+0

Правильный ответ, указывая мне на «Складную». –

3

только две абстракции «пустота» Я думаю, что на верхней части моей головы:

Во-первых, MonadError: Maybe может иметь instance MonadError() Maybe. См однако https://github.com/ekmett/mtl/issues/27

Во-вторых, lens_Empty, , который по сравнению по умолчанию (Eq) с mempty (из Monoid). Однако Monoid и Alternative не согласны для Maybe.

Но я не помню ни одного оператора, непосредственно работающего над одним из вышеперечисленных.

3

На самом деле, мне не нравится <?> имя оператора за то, что вы ищете. Если вы ищете Maybe a -> a -> a тип на Stackage или Hayoo?: Оператор из errors упаковка.

И этот оператор так называется elvis -оператор. Он используется в Groovy в этой форме.И Kotlin также получил это. Этот оператор помогает справляться с нулями в императивном языке. Но если вы представляете, что Maybe a является своего рода нулевым типом, то оператор ?: имеет смысл и для вас. Вы можете наблюдать за тем, что есть какая-то история за оператором ?:.

Кроме того, <?> уже используется в некоторых пакетах, как megaparsec, attoparsec, optparse-generic и другие. И ваш проект может использовать один из них с большой вероятностью. Таким образом, вы можете столкнуться с некоторыми конфликтами, используя вашу версию elvis -оператор.

+0

О, конечно, '?:' Был бы более разумным выбором. –