#haskell
#haskell
Вопрос:
У меня есть функция
mySucc :: (Enum a, Bounded a, Eq a, Show a) => a -> Maybe a
mySucc int
| int == maxBound = Nothing
| otherwise = Just $ succ int
Когда я хочу распечатать выходные данные этой функции в ghci, Haskell, похоже, запутался в том, какой экземпляр Show использовать. Почему это? Разве Haskell не должен автоматически разрешать тип a во время выполнения и использовать его Show?
Мое ограниченное понимание класса типа заключается в том, что, если вы упоминаете тип (в моем случае a) и говорите, что он принадлежит классу типа (Show), Haskell должен автоматически разрешить тип. Разве не так он разрешает Bounded, Enum и Eq? Пожалуйста, поправьте меня, если я неправильно понимаю.
Комментарии:
1. Как вы вызываете эту функцию в GHCi?
2. Привет, это с помощью «stack ghci»
Ответ №1:
Разве Haskell не должен автоматически разрешать тип a во время выполнения и использовать его
Show
?
Вообще говоря, типы не существуют во время выполнения. Компилятор проверяет тип вашего кода, устраняет любой полиморфизм, а затем удаляет типы. Но это отчасти ортогонально вашему основному вопросу.
Мое ограниченное понимание класса типа заключается в том, что, если вы упоминаете тип (в моем случае
a
) и говорите, что он принадлежит классу типа (Show
), Haskell должен автоматически разрешить тип
Нет. Компилятор автоматически разрешит экземпляр. Это означает, что вам не нужно явно передавать showing-метод в вашу функцию. Например, вместо функции
showTwice :: Show a => a -> String
showTwice x = show x show x
у вас могла бы быть функция, которая не использует никакого класса типов
showTwice' :: (a -> String) -> a -> String
showTwice' show' x = show' x show' x
который можно использовать почти так же, как showTwice
если вы дадите ему стандартный show
в качестве первого аргумента. Но этот аргумент нужно было бы передавать вручную на каждом сайте вызова. Это то, чего вы можете избежать, используя вместо этого класс type , но для этого все еще требуется, чтобы тип был известен первым.
(Ваш mySucc
на самом деле не использует show
ни в коем случае вообще, так что вы могли бы также полностью опустить Show a
ограничение.)
Когда ваш вызов mySucc
появляется в более крупном выражении, скорее всего, тип будет фактически также выведен автоматически. Например, mySucc (length "bla")
будет использовать a ~ Int
, потому что результат length
фиксирован на Int
; или mySucc 'y'
будет использовать a ~ Char
. Однако, если все подвыражения полиморфны (а в Haskell литералы четного числа полиморфны), то компилятор не будет иметь никаких указаний на то, какой тип вы на самом деле хотите. В этом случае вы всегда можете указать его явно, либо в аргументе
> mySucc (3 :: Int)
Just 4
или в результате
> mySucc 255 :: Maybe Word8
Nothing
Комментарии:
1. Теперь я понимаю, что когда мы используем «test :: (Eq a) -> a -> a», это означает, что a относится к любому экземпляру, который реализует все (обязательные) методы, описанные в Eq. Спасибо за объяснение
2. ДА. Я в основном просто имею в виду, что вы сможете использовать
==
внутри определенияtest
, даже если вы не знаете, какого типа это на данный момент. Но компилятору действительно нужно знать тип, когдаtest
используется в реальной программе.
Ответ №2:
Ты пишешь mySucc 1
? В этом случае вы получаете ошибку, потому что 1
литерал является полиморфным значением типа Num a => a
.
Попробуйте вызвать mySucc 1 :: Maybe Int
, и это сработает.