Haskell развернуть Может сохранить полиморфизм
Начинающий Хаскель здесь снова. Если я хочу развернуть Maybe
введите и хотите сохранить его абстрактным, я бы использовал:
fUnwrap :: Maybe a -> a
fUnwrap (Just n) = n
fUnwrap Nothing = ???
Неважно, что я делаю с Nothing
, компилятор продолжает настаивать на том, чтобы быть более конкретным в том, что делать с Nothing
... Можете ли вы, ребята, помочь мне?
2 ответа
Это логично. Компилятор отображает значение типа a
, но здесь нет никакой ценности, которую вы можете предоставить, так как a
может быть что угодно (Bool
, Int
, [Int]
, Maybe Int
, так далее.).
Это не столько проблема программирования, сколько проблема проектирования: что вы хотите сделать, если это Nothing
? Здесь есть несколько вариантов:
предоставив значение по умолчанию, поэтому подпись будет такой:
fUnwrap :: a -> Maybe a -> a fUnwrap _ (Just n) = n fUnwrap d Nothing = d
мы поднимаем ошибку в случае, если это
Nothing
(мы можем сделать это либо оставив строку, либо явно выдав ошибку, хотя в последнем случае мы можем указать причину):fUnwrap :: Maybe a -> a fUnwrap (Just n) = n fUnwrap Nothing = error "Nothing has no value"
мы возвращаемся
undefined
:fUnwrap :: Maybe a -> a fUnwrap (Just n) = n fUnwrap Nothing = undefined
undefined :: a
это объект, который вызывает ошибку, если он оценивается. Таким образом, это особый случайerror
, но мы "откладываем" оценку так, что если значение не нужно, мы не получим ошибку.
Но лично я думаю, что первый подход здесь целесообразен, так как сигнатуры функций не указывают, что они могут вызвать ошибку, поэтому он может привести к сбою кода, не имея намека на то, что может.
Maybe a
обычно используется как тип результата вычисления, которое может "потерпеть неудачу": в случае успеха оно возвращает Just x
(с x
результат), а в противном случае он возвращает 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.