`fail" zero '`как способ генерирования Nothing в простом примере` a -> Maybe a` - PullRequest
0 голосов
/ 17 мая 2019

Я читаю показательный пример использования оператора связывания :

Just 5 >>= (\ x -> if (x == 0) then fail "zero" else Just (x + 1) )

возвращает Just 6.

Меня смущает поведениеfail и его полезность в примере.Глядя на код, я подумал, что fail "zero" может иметь значение:

  • программа никогда не достигает этой точки
  • лень
  • что-то еще.

Затем я понял, что после объединения типов исключение становится Nothing (задокументировано здесь ).Меня по-прежнему смущает, что без принудительного ввода типов fail это просто ошибка в программе.

Prelude> fail "zero" :: Maybe Int
Nothing
Prelude> fail "abc" :: [Int]
[]
Prelude> fail "zero"
*** Exception: user error (zero)

Мой вопрос касается полезности fail "zero" в этом примере.

Правильное ли чтение (\ x -> if (x == 0) then fail "zero" else Just (x + 1) ) пытается быть простым случаем для функции a -> Maybe a?

Что мешает нам использовать (\ x -> if (x == 0) then Nothing else Just (x + 1) ), если нам просто нужна была иллюстрация a -> Maybe a?

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

Prelude> g x = if (x == 0) then Nothing else Just (x + 1)
Prelude> Just 0 >>= g
Nothing
Prelude> Just 1 >>= g
Just 2

Ответы [ 2 ]

6 голосов
/ 17 мая 2019

Это правильное чтение (\ x -> if (x == 0) then fail "zero" else Just (x + 1) ) пытается быть простым случаем для a -> Maybe a функции?

Да.

Что мешает нам использовать (\ x -> if (x == 0) then Nothing else Just (x + 1) ), если нам просто нужна была иллюстрация a -> Maybe a?

Ничего.

4 голосов
/ 17 мая 2019

Чтобы уточнить совершенно правильный ответ Даниэля, fail - это функция из класса типов MonadFail.Первоначально он был в классе типов Monad, но на самом деле он там не принадлежал, так как у некоторых Monad нет концепции отказа.Для тех, у кого есть концепция отказа, fail имеет тип MonadFail m => String -> m a.То есть для любого типа, который реализует интерфейс MonadFail, и для любого типа a, fail может взять строку и создать экземпляр этого типа, параметризованный как a.

Для Maybe a, fail s = Nothing.

Для [a], fail s = [].

Для IO a, fail вызывает исключение, содержащее строку.

Многие людинапишите экземпляры MonadFail для таких типов, как Either String a, где fail s = Left s.Основная причина, по которой это не входит в стандартную библиотеку, заключается в том, что Either является довольно абстрактным типом, и хотя обычно Right считается успешным, а Left - неудачным, его можно разумно использовать как Monadс перевернутой семантикой.(Например, если вы хотите попробовать N вещей и перейти к следующему, если что-то не получится, но примите первый результат, вам нужно использовать Left в качестве примера успеха.)

Редактировать:

Кроме того, когда вы пишете некоторый код, такой как

do 
  Just y <- getMaybe x
  return y

, который обнуляется:

do
  case getMaybe x of
    Just y -> return y
    _      -> fail "Failed pattern match"

Это означает, что неудачное сопоставление с шаблоном вызовет исключениев IO a, но быть пустым списком в [a] и Nothing в Maybe a.

...