Haskell развернуть Может сохранить полиморфизм

Начинающий Хаскель здесь снова. Если я хочу развернуть Maybe введите и хотите сохранить его абстрактным, я бы использовал:

fUnwrap :: Maybe a -> a 
fUnwrap (Just n) = n 
fUnwrap Nothing = ???

Неважно, что я делаю с Nothing, компилятор продолжает настаивать на том, чтобы быть более конкретным в том, что делать с Nothing... Можете ли вы, ребята, помочь мне?

2 ответа

Решение

Это логично. Компилятор отображает значение типа a, но здесь нет никакой ценности, которую вы можете предоставить, так как a может быть что угодно (Bool, Int, [Int], Maybe Int, так далее.).

Это не столько проблема программирования, сколько проблема проектирования: что вы хотите сделать, если это Nothing? Здесь есть несколько вариантов:

  1. предоставив значение по умолчанию, поэтому подпись будет такой:

    fUnwrap :: a -> Maybe a -> a 
    fUnwrap _ (Just n) = n
    fUnwrap d Nothing = d
  2. мы поднимаем ошибку в случае, если это Nothing (мы можем сделать это либо оставив строку, либо явно выдав ошибку, хотя в последнем случае мы можем указать причину):

    fUnwrap :: Maybe a -> a
    fUnwrap (Just n) = n
    fUnwrap Nothing = error "Nothing has no value"
  3. мы возвращаемся undefined:

    fUnwrap :: Maybe a -> a
    fUnwrap (Just n) = n
    fUnwrap Nothing = undefined

    undefined :: a это объект, который вызывает ошибку, если он оценивается. Таким образом, это особый случай error, но мы "откладываем" оценку так, что если значение не нужно, мы не получим ошибку.

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

Maybe a обычно используется как тип результата вычисления, которое может "потерпеть неудачу": в случае успеха оно возвращает Just xx результат), а в противном случае он возвращает Nothing,

Вы можете использовать, например, do нотация для построения Maybe a из цепочки вычислений, которые могут потерпеть неудачу. Например:

foo :: Int -> Maybe Int
foo x = do
    y <- someComputation x
    otherComputation y

с приведенным здесь примером someComputation, otherComputation :: Int -> Maybe Int,

Это невозможно, так как ваша функция написана. Поскольку функция чистая, вы не можете вернуть a, поскольку ваш единственный ввод - Nothing.

Прелесть Maybe в том, что вам не нужно его "разворачивать". Вы можете использовать функцию fmap для работы с упакованными данными, только если они существуют, и неявным образом ничего не делать в случае Nothing.

Другие вопросы по тегам