当我尝试提取数字的前两位数时,我遇到了令人沮丧的错误。首先,我使用log计算出数字的长度,然后我将数字除以10^(length of digit - 2)
以提取前两位数字。 len和除数函数工作正常,但firstTwo函数失败,我不明白这一点,因为它似乎很直接。我甚至尝试添加{-# 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
答案 0 :(得分:3)
您在div
和n
上使用divisor
,但divisor
与n
的类型不同,它是一个功能。这就是为什么你最终得到Integral (r -> a)
。
使用firstTwo n = div n (divisor n)
,但请注意,logBase
仅适用于Floating
,例如Double
和Float
,而div
仅适用在Integral
上,例如Integer
和Int
。因此,除非您更改了len
的类型,否则它仍然无法编译。
为您的函数添加类型签名以获得更好的错误消息。
答案 1 :(得分:3)
由于您似乎是初学者,我的第一个建议是尽可能多地添加类型信息。至少对于每个顶级(功能)定义。这有助于您,编译器和阅读代码的其他人了解您的意图。
现在解决您的问题:您尝试将数字n
除以函数divisor
div n (divisor n)
应该做的诀窍是,有一小部分缺失 - logBase
对整数不起作用,而div
只对整数有效。因此,您需要先致电fromInteger
进行转换。
对负数进行小幅度调整的替代方法可能是take 2 . show
。
答案 2 :(得分:1)
将您的号码转换为字符串。
检查字符串是否包含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"