Haskell показывает класс типа в функции

#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 , и это сработает.