2012-04-29 5 views
5

Я не понимаю, почему следующая функция работает:Путаница с умозаключения типа Haskell

isLongerThanN :: Integral n => n -> [a] -> Bool 
isLongerThanN n xs = length xs > fromIntegral n 

но следующий не будет:

isLongerThanN' :: Integral n => n -> [a] -> Bool 
isLongerThanN' n xs = length xs > n 

, который бросает ошибку

Could not deduce (n ~ Int) 
    from the context (Integral n) 
     bound by the type signature for 
       isLongerThanN' :: Integral n => n -> [a] -> Bool 
     at blah.hs:140:1-35 
     `n' is a rigid type variable bound by 
      the type signature for 
      isLongerThanN' :: Integral n => n -> [a] -> Bool 
      at blah.hs:140:1 
    In the second argument of `(>)', namely `n' 
    In the expression: length xs > n 
    In an equation for `isLongerThanN'': 
     isLongerThanN' n xs = length xs > n 

(что я, вероятно, неправильно понял)

Во всяком случае, я ожидаю, что это будет наоборот, поскольку fromIntegral эффективно расширяет тип переменной n.

+8

Не пишите 'если Foo то правда еще false'. Это то же самое, что просто 'foo'. – hammar

+1

вы правы, спасибо; Я изменил его, но это не вопрос – Inept

+4

Вот почему он не опубликовал его как ответ ... – Jasper

ответ

12

Рассмотрим выражение, которое не работает

isLongerThanN' :: Integral n => n -> [a] -> Bool 
isLongerThanN' n xs = length xs > n 

n может быть любым целым числом, у типа, поэтому он может быть передан в Integer или Word или Int. (>) имеет тип Ord a => a -> a -> Bool, поэтому оба его левого и правого операнда должны быть одного типа. length xs возвращает Int, поэтому этот тип должен быть таким. Но, n может быть любым Integral, не обязательно Int, поэтому нам нужно каким-то образом разрешить n преобразовать в Int. Это то, что делает fromIntegral (факт, что он также позволяет n быть любым Num в основном не имеет значения).

Мы могли бы расширить рабочую версию, чтобы выглядеть следующим образом:

toInt :: Integral n => n -> Int 
toInt = fromIntegral 

isLongerThanN :: Integral n => n -> [a] -> Bool 
isLongerThanN n xs = length xs > toInt n 

, что делает его более ясным, что мы используем специализированную версию fromIntegral.

(Обратите внимание, что isLongerThanN n xs = fromIntegral (length xs) > n также работает, потому что это позволяет результат length в соответствии с типом n.)

+2

Хотя, обратите внимание, что выбор, который вы конвертируете, может повлиять на результат; с последним примером 'isLongerThanN (0 :: Word8) [1..256] == False' из-за переполнения. – hammar

+0

О, ладно, я понимаю. Большое спасибо. Почему нерабочая версия не работает, не проблема для меня, но я неправильно читал подпись типа из Integral :: (Num b, Integral a) => a -> b. – Inept

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