#haskell
#haskell
Вопрос:
Не удалось действительно следовать выводам типа ниже, где случай 1 сработал, но случай 2 не удался, почему?
ghci> :t sqrt . maximum . map ( 1) -- case 1
(Floating c, Ord c) => [c] -> c
ghci> :t sqrt . maximum . map length -- case 2
Could not deduce (Floating Int) arising from a use of ‘sqrt’
from the context (Foldable t)
bound by the inferred type of it :: Foldable t => [t a] -> Int
@РЕДАКТИРОВАТЬ
В ООП Num
обычно является нижней границей для всех его subtypes
, например Int
, и Float
. Следовательно, Int
будет логически приемлемым, если Num
является квалифицированным типом, но не наоборот.
Кроме того, на C-подобных языках встроенное преобразование чисел может автоматически выполнять регистр с более низкой точностью до более высокой, например, от Int
до Float
.
В отличие от этого, в Haskell с системой типов HM Num
является class
для всех его instances
, например Int
, и subclasses
, например Floating
. Квалифицированные типы могут быть выведены между предком и потомком, например, от Num
до Int
, Floating
или наоборот, но не между Int
и Floating
.
Чтобы исправить случай 2, Int
сначала его следует адаптировать к Num
by fromIntegral
или приложить Data.List.genericLength
усилия для создания Num
— логически квалифицированного типа для Floating
этого sqrt
требуется.
Давайте применим вышеупомянутые пункты, чтобы следовать выводам типа ниже,
ghci> :t ( )
Num a => a -> a -> a
ghci> :t 1.1
Fractional a => a
ghci> :i Fractional
class Num a => Fractional a
instance Fractional Float
instance Fractional Double
ghci> :t 1
Num a => a
ghci> :t length [1]
Int
ghci> :i Int
instance Num Int
instance Real Int
instance Integral Int
ghci> :t 1.1 1 -- case 1
Fractional a => a
ghci> :t 1.1 length [1] -- case 2
No instance for (Fractional Int) arising from the literal ‘1.1’
Комментарии:
1.
length
Функция возвращаетInt
, ноsqrt
ожидает тип сFloating
экземпляром. ПопробуйтеgenericLength
Data.List
вместо этого использовать from , который может создавать любой тип сNum
экземпляром.2. Ваше резюме неверно. Классы типов не являются типами. Вы не можете преобразовать Num в Int или Int в Floating. Это яблоки и апельсины. Классы типов ограничивают тип. У вас может быть, например,
Floating a => a -> a -> a
который говорит, чтоa
должен иметь плавающий экземпляр.Float
делает,Int
не делает.3. @erisco, дело
type inference
в том, что моя формулировка может ввести вас в заблуждение, заставляя думать о преобразовании междуtype class
и т.д.type
4. Литерал
1
может быть выведен как любой тип Num. В первом случаеsqrt
имеет ограничение с плавающей запятой и1
ограничение Num, что упрощает просто ограничение с плавающей запятой (потому что плавающее значение подразумевает Num). Во втором случаеlength
имеет ограничение(~) Int
, но оно не выполняется, посколькуInt
не имеет плавающего экземпляра.5. Также я должен добавить,
fromIntegral
ослабляет интегральное ограничение на ограничение Num.fromIntegral :: (Num b, Integral a) => a -> b
. Возможно, этого не должно быть из-за неблагоприятных последствий, таких какfromIntegral 1000 :: Word8
.
Ответ №1:
1
может быть любым типом числа и
может работать с любым типом числа. То же самое верно для maximum
. Таким образом maximum . map ( 1)
, функция, которая может, может принимать список чисел любого типа и выдавать число того же типа, что и его результат. Это включает в себя как целые числа, так и числа с плавающей запятой.
Однако length
, в частности, приведет Int
к . Он не может выдавать числа любого другого типа. So maximum . map length
может взять любой список и выдать результат типа Int
, а не какого-либо другого числового типа.
Теперь sqrt
его аргументом должно быть число с плавающей запятой. Итак, в первом случае вывод типа показывает, что вы должны предоставить список чисел с плавающей запятой, поэтому результатом maximum . map ( 1)
будет число с плавающей запятой, которому можно передать sqrt
.
Однако второй случай просто не может работать, потому Int
что не является типом с плавающей запятой и maximum . map length
не может выдавать ничего, кроме an Int
. Таким образом, это вызывает ошибку.
Вы можете использовать fromIntegral
функцию для преобразования результата length
в любой числовой тип, чтобы заставить второй код работать.
Комментарии:
1. не могли бы вы любезно взглянуть на мой отредактированный пост, чтобы проверить, правильно ли он обобщен? Спасибо!