Хаскель разыгрывает Integer в Int - PullRequest
0 голосов
/ 04 октября 2018

Почему первый правильный, а второй нет?Я хотел бы реализовать код вторым способом, чтобы мне не приходилось каждый раз звонить из Integer, но я не понимаю, как ...

Исправить

bits :: Integer -> Int 
bits 0 = 0
bits n = fromInteger n `mod` 2 + bits(fromInteger n `div` 2) 

Неверно

bits :: Integer -> Int 
bits 0 = 0
bits n = let m = fromInteger n in m `mod` 2 + bits(m `div` 2) 

Ответы [ 3 ]

0 голосов
/ 04 октября 2018

Вы можете немного подправить подпись и избавиться от всех fromInteger s.

bits :: Integral a => a -> a 
bits 0 = 0
bits n = n `mod` 2 + bits (n `div` 2)
0 голосов
/ 05 октября 2018

Вот причина, по которой эта версия не проверяет тип:

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.

0 голосов
/ 04 октября 2018

Поскольку он вам не нужен для второго вызова:

bits :: Integer -> Int 
bits 0 = 0
bits n = fromInteger n `mod` 2 + bits (n `div` 2) 

Второй fromInteger просто привел к Integer снова, что было установлено параметром bits.

...