[редактировать от автора, 6 лет спустя] Это излишне длинный ответ, и я не уверен, почему он был принят.Используйте maybe
или Data.Maybe.fromMaybe
, как предложено в ответе с наибольшим количеством голосов.Далее следует скорее мысленный эксперимент, а не практический совет.
Итак, вы пытаетесь создать функцию, которая работает для группы разных типов.Это хорошее время, чтобы сделать класс.Если вы программировали на Java или C ++, класс в Haskell является своего рода интерфейсом в этих языках.
class Nothingish a where
nada :: a
Этот класс определяет значение nada
, которое должно быть эквивалентным классуNothing
.Теперь самое интересное: создание экземпляров этого класса!
instance Nothingish (Maybe a) where
nada = Nothing
Для значения типа Maybe a
значение типа Nothing равно ну, Nothing
!Это будет странный пример через минуту.Но до этого давайте сделаем списки экземпляром этого класса тоже.
instance Nothingish [a] where
nada = []
Пустой список вроде как Ничего, верно?Таким образом, для String (который является списком Char) будет возвращена пустая строка, ""
.
Числа также являются простой реализацией.Вы уже указали, что 0, очевидно, представляет «Ничто» для чисел.
instance (Num a) => Nothingish a where
nada = 0
Это на самом деле не будет работать, если вы не поместите специальную строку вверху вашего файла
{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-}
Или когда вы его компилируете, вы можете установить флаги для этих языковых прагм.Не беспокойтесь о них, они просто волшебство, которое заставляет больше работать.
Итак, теперь у вас есть этот класс и его экземпляры ... теперь давайте просто переписаем вашу функцию для использованияих!
eliminate :: (Nothingish a) => Maybe a -> a
eliminate (Just a) = a
eliminate Nothing = nada
Обратите внимание, я только изменил 0
на nada
, а остальное тоже самое.Давайте попробуем!
ghci> eliminate (Just 2)
2
ghci> eliminate (Just "foo")
"foo"
ghci> eliminate (Just (Just 3))
Just 3
ghci> eliminate (Just Nothing)
Nothing
ghci> :t eliminate
eliminate :: (Nothingish t) => Maybe t -> t
ghci> eliminate Nothing
error! blah blah blah...**Ambiguous type variable**
Отлично смотрится на ценности и прочее.Заметьте, что (Просто Ничто) превращается в Ничто, понимаете?Это был странный пример, «Может быть, в Возможно».В любом случае ... как насчет eliminate Nothing
?Ну, результирующий тип неоднозначен.Он не знает, что мы ожидаем.Таким образом, мы должны сказать ему, какой тип нам нужен.
ghci> eliminate Nothing :: Int
0
Попробуйте и попробуйте его для других типов;вы увидите, что он получает nada
для каждого.Итак, теперь, когда вы используете эту функцию с вашей combine
функцией, вы получаете следующее:
ghci> let combine a b c = (eliminate a, eliminate b, eliminate c)
ghci> combine (Just 2) (Just "foo") (Just (Just 3))
(2,"foo",Just 3)
ghci> combine (Just 2) Nothing (Just 4)
error! blah blah Ambiguous Type blah blah
Обратите внимание, что вам все равно нужно указать, какой тип у вас "Nothing", или указать, какой тип возвращаемого значения вы ожидаете.
ghci> combine (Just 2) (Nothing :: Maybe Int) (Just 4)
(2,0,4)
ghci> combine (Just 2) Nothing (Just 4) :: (Int, Int, Int)
(2,0,4)
Или вы можете ограничить типы, разрешенные вашей функцией, явно указав сигнатуру типа в источнике.Это имеет смысл, если логически использовать функцию так, чтобы она использовалась только с параметрами одного типа.
combine :: (Nothingish a) => Maybe a -> Maybe a -> Maybe a -> (a,a,a)
combine a b c = (eliminate a, eliminate b, eliminate c)
Теперь она работает, только если все три вещи Maybe одного типа.Таким образом, это будет означать, что Nothing
того же типа, что и другие.
ghci> combine (Just 2) Nothing (Just 4)
(2,0,4)
Нет двусмысленности, ура!Но теперь ошибочно смешивать и сопоставлять, как мы делали раньше.
ghci> combine (Just 2) (Just "foo") (Just (Just 3))
error! blah blah Couldn't match expected type blah blah
blah blah blah against inferred type blah blah
Ну, я думаю, что это был достаточно длинный и раздутый ответ.Наслаждайтесь.