Haskell将Integer转换为Int

时间:2018-10-04 10:34:28

标签: haskell casting integer

为什么第一个正确而第二个不正确? 我想用第二种方式实现代码,这样就不必每次都从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 :(得分:2)

因为您不需要第二次通话:

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

由于参数强制fromInteger,第二个Integer只是简单地再次产生了bits

答案 1 :(得分:1)

以下是此版本未进行类型检查的原因:

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

首先,请注意,m的首次使用要求mInt,因为bits调用的结果必须是Int表示加法项的左侧(即m `mod` 2)必须为Int。为什么是这样?好吧,这是因为+运算符的签名是:

(+) :: (Num a) => a -> a -> a

,它要求+的两个参数都具有与其结果相同的类型。同样,由于m `mod` 2必须是Int,因此`mod`调用的左侧(即m)必须是Int,因为{{1 }}具有签名:

mod

因此,这就是mod :: (Integral a) => a -> a -> a 首次使用需要m的原因。哇!

出于相同的原因,m :: Int second 使用要求mm。这是因为表达式{{1}中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 可以同时用作mm。但是,由于一种叫做“单态性限制”的事情,没有显式的类型签名,因此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了。

答案 2 :(得分:0)

您也许可以对签名进行一些调整,并摆脱所有fromInteger

bits :: Integral a => a -> a 
bits 0 = 0
bits n = n `mod` 2 + bits (n `div` 2)
相关问题