Вот причина, по которой эта версия не проверяет тип:
bits :: Integer -> Int
bits 0 = 0
bits n = let m = fromInteger n in m `mod` 2 + bits(m `div` 2)
Во-первых, обратите внимание, что первое использование m
требует, чтобы m
было Int
, потому что результатbits
call должен быть Int
, что означает, что левая часть дополнения (а именно m `mod` 2
) должна быть Int
.Почему это?Ну, это потому, что подпись оператора +
:
(+) :: (Num a) => a -> a -> a
, которая требует, чтобы оба аргумента +
имели тот же тип, что и его результат.Точно так же, поскольку m `mod` 2
должен быть Int
, левая сторона вызова `mod`
(а именно m
) должна быть Int
, потому что mod
имеет подпись:
mod :: (Integral a) => a -> a -> a
Итак, поэтому первое использование m
требует m :: Int
.Вот так!
По той же причине, секунда использование m
требует, чтобы m
было Integer
.Это потому, что аргумент bits
в выражении bits (m `div` 2)
должен быть Integer
, который требует, чтобы левая часть оператора `div`
была Integer
.
Следовательно, мы имеемтребование, чтобы m
было и Int
, и Integer
.Это не обязательно проблема.Если вместо этого вы написали:
bits :: Integer -> Int
bits 0 = 0
bits n = m `mod` 2 + bits(m `div` 2)
where m :: (Integral a) => a
m = fromInteger n
и дали m
явную полиморфную сигнатуру типа, тогда m
можно использовать как Int
и и Integer
одновременно.Однако из-за того, что называется ограничением мономорфизма, без явной сигнатуры типа, m
должен иметь один неполиморфный тип (т. Е. Мономорфный тип).Если вы добавите прагму:
{-# LANGUAGE NoMonomorphismRestriction #-}
в начало вашего файла, тогда тип проверки оригинального определения будет хорошо:
{-# LANGUAGE NoMonomorphismRestriction #-}
bits :: Integer -> Int
bits 0 = 0
bits n = let m = fromInteger n in m `mod` 2 + bits(m `div` 2)
Однако другие отметили, что вы на самом деле этого не делаетенужно fromInteger
в обоих местах;и что одновременное использование Int
и Integer
не нужно, а использование одного целочисленного типа с ограничением (Integral a
) может быть еще лучше.
Кроме того, если вы хотитеэта функция для реальной работы, а не просто для практики, она уже доступна как popCount
в модуле Data.Bits
.