提取数字哈斯克尔的前两位数字



当我尝试提取数字的前两位数字时,我遇到了一个令人沮丧的错误。首先,我使用 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

你在ndivisor上使用div,但divisorn的类型不同,它是一个函数。这就是为什么你最终会得到Integral (r -> a).

使用firstTwo n = div n (divisor n),但请记住,logBase仅适用于DoubleFloatFloating,而div仅适用于IntegerIntIntegral。因此,除非您更改了len的类型,否则它仍然无法编译。

向函数添加类型签名以获取更好的错误消息。

由于您似乎是初学者,我的第一个建议是尽可能多地添加类型信息。至少对于每个顶级(函数)定义。这有助于您、编译器和阅读代码的其他人理解您的意图。

现在到你的问题:你尝试将一个n的数字除以一个函数divisor

div n (divisor n)

应该可以解决问题,嗯,缺少一小块 -logBase不适用于整数,而div仅适用于整数。因此,您需要先致电fromInteger进行转换。

可以take 2 . show对负数进行小幅调整的替代方案。

  1. 将您的数字转换为字符串。

  2. 检查字符串是否包含 2 个或更多字符。

  3. 如果检查成功,请从字符串中取出前 2 个字符并将它们转换为 Int(或将这些字符放在元组中或随心所欲地处理它们)。

  4. 如果您的号码包含少于 2 位数字(例如抛出错误),请对大小写进行处理。

    firstTwo :: Integer -> Int
    firstTwo n
    | (length . show $ n) >= 2 = read . take 2 . show $ n
    | otherwise = error "The number contains less than 2 digits"
    

最新更新