为什么第一个正确而第二个不正确? 我想用第二种方式实现代码,这样就不必每次都从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)
答案 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
的首次使用要求m
是Int
,因为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 使用要求m
是m
。这是因为表达式{{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
可以同时用作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
了。
答案 2 :(得分:0)
您也许可以对签名进行一些调整,并摆脱所有fromInteger
。
bits :: Integral a => a -> a
bits 0 = 0
bits n = n `mod` 2 + bits (n `div` 2)