2017-02-21 2 views
2

У меня есть следующий тип подписи:Почему (Num а, Ord а) => а

let kessel :: (Ord a, Num b) => a -> b -> a; kessel = undefined 

Когда я попросил типа результата:

:t kessel 1 2 

Я получил:

kessel 1 2 :: (Num a, Ord a) => a 

Почему не Integer?

+0

Это будет 'Integer' если вы уверить компилятор, что первый аргумент является' Integer', не является '' Int' Double' и т. Д. Итак, ': t kessel (1 :: Integer) 2' является' Integer' – Michael

+0

Почему я не получаю просто 'Num' вместо' (Num a, Ord a) => a' –

+1

Только первый аргумент вопросы. Это должно быть «Орд», потому что ты этого требовал. Это должно быть 'Num', потому что вы использовали числовой литерал. – Michael

ответ

9

Поскольку 1 имеет тип Num a => a:

ghci> :t 1 
1 :: Num a => a 
ghci> :t kessel 
kessel :: (Num b, Ord a) => a -> b -> a 
ghci> :t kessel 1 
kessel 1 :: (Num a, Num b, Ord a) => b -> a 
ghci> :t kessel 1 2 
kessel 1 2 :: (Num a, Ord a) => a 

Ограничения, из 1 (Num) получить добавил к уже существующим. Это то же самое, когда вы используете id, например:

id :: a -> a 
id 1 :: Num a => a 

Longer объяснение

При использовании kessel :: (Ord a, Num b) => a -> (b -> a) вы сообщаете компилятору, что kessel будет принимать любойa, что является экземпляром Ord. kessel затем возвращает функцию от любой другой (необязательно другой) тип b, то есть также экземпляр Num ранее упомянутому типу a.

Это означает, что первый аргумент используется для kessel установит a:

ghci> :t kessel (1 :: Int) 
kessel (1 :: Int) :: Num b => b -> Int 
ghci> :t kessel 'A' 
kessel 'A' :: Num b => b -> Char 
ghci> :t kessel "Hello, World!" 
kessel "Hello, World!" :: Num b => b -> String 

Во всех этих случаях типа аргумента был ясен. Но что, если мы используем значение, которое является полиморфным? Например, это один:

magic :: Magic a => a 

А также давайте использовать более простую функцию, а именно: const

const :: a -> b -> a 
const x y = x 

Что const magic? Давайте начнем проще. Что такое const "Hello, World?"?

const     :: a  -> b -> a 
"Hello, World?"  :: String 
const "Hello, World?" ::   b -> String 

Мы заменили каждый вхождение a с типом "Hello, World?" «s. Теперь вернемся к нашему magic например:

const  ::   a -> b -> a 
magic  :: Magic t => t 
const magic :: Magic t =>  b -> t 

Снова, мы заменим каждое вхождение a с нашего типа, в данном случае t. Однако мы не должны забывать о дополнительном ограничении на t, а именно Magic. Мы должны принести это. Поэтому мы получаем дополнительное ограничение здесь. Но если бы было какое-то ограничение на a, нам все равно нужно разместить их до t.

Давайте теперь вернемся к исходному kessel:

kessel :: (Num b, Ord a  ) => a -> b -> a 
1  :: (Num n    ) => n 
kessel 1 :: (Num na, Ord na, Num b) =>  b -> na 

Мы еще держать a «s оригинальный ограничение. Поэтому теперь у нас есть два ограничения: Num и Ord. Если мы теперь используем любой тип, который соответствует ограничению Num, все, что у нас осталось, это na. Так как это не на правой стороне больше, ее ограничение может быть отброшено:

kessel 1 2 :: (Num na, Ord na) => na 
+0

Как я могу прочитать 'kessel 1 :: (Num a, Num b, Ord a) => b -> a'? Почему я могу удалить 'b' здесь' kessel 1 2 :: (Num a, Ord a) => a'? Я не могу исключить 'a' здесь' kessel 1 2 :: (Num a, Ord a) => a', потому что он все еще связан? –

+0

Результат 'id 1 :: Num a => a' будет экземпляром' Num'? Что такое наследование Context из класса (оператор '=>') означает? –

+0

Вы можете исключить 'a' в' kessel 1 2 :: (Num a, Ord a) => a', сообщая компилятору, что вы имеете в виду под '1', например. 'kessel (1 :: Integer) 2 :: Целое число. Поскольку он стоит, числовой литерал может быть в любом числовом типе' a', что и означает 'Num a => ...'. – Michael

Смежные вопросы