当我尝试提取数字的前两位数字时,我遇到了一个令人沮丧的错误。首先,我使用 log 计算出数字的长度,然后将数字除以10^(length of digit - 2)
以提取前两位数字。len 和除数函数工作正常,但前两个函数失败了,我不明白这一点,因为它看起来很简单。我什至尝试添加{-# LANGUAGE FlexibleContexts #-}
,但什么都没有。 请协助。代码如下:
len n = (+) 1 $ truncate $ logBase 10 n -- length of a digit
divisor n = 10 ^ (len n - 2)
firstTwo n = div n divisor
我得到的错误是:
约束中的非类型变量参数:Integral (r -> a)
(Use FlexibleContexts to permit this)
When checking that ‘firstTwo’ has the inferred type
firstTwo :: forall a r.
(Floating r, Integral (r -> a), Num a, RealFrac r) =>
(r -> a) -> r -> a
你在n
和divisor
上使用div
,但divisor
与n
的类型不同,它是一个函数。这就是为什么你最终会得到Integral (r -> a)
.
使用firstTwo n = div n (divisor n)
,但请记住,logBase
仅适用于Double
和Float
等Floating
,而div
仅适用于Integer
和Int
等Integral
。因此,除非您更改了len
的类型,否则它仍然无法编译。
向函数添加类型签名以获取更好的错误消息。
由于您似乎是初学者,我的第一个建议是尽可能多地添加类型信息。至少对于每个顶级(函数)定义。这有助于您、编译器和阅读代码的其他人理解您的意图。
现在到你的问题:你尝试将一个n
的数字除以一个函数divisor
div n (divisor n)
应该可以解决问题,嗯,缺少一小块 -logBase
不适用于整数,而div
仅适用于整数。因此,您需要先致电fromInteger
进行转换。
可以take 2 . show
对负数进行小幅调整的替代方案。
-
将您的数字转换为字符串。
-
检查字符串是否包含 2 个或更多字符。
-
如果检查成功,请从字符串中取出前 2 个字符并将它们转换为 Int(或将这些字符放在元组中或随心所欲地处理它们)。
-
如果您的号码包含少于 2 位数字(例如抛出错误),请对大小写进行处理。
firstTwo :: Integer -> Int firstTwo n | (length . show $ n) >= 2 = read . take 2 . show $ n | otherwise = error "The number contains less than 2 digits"