【问题标题】:Removing digits from an integer从整数中删除数字
【发布时间】:2018-06-20 03:42:45
【问题描述】:

这是我遇到的一个家庭作业问题:

输入一个大于等于0的整数。乘以5,乘以6,乘以4,加9,乘5。然后,去掉最后两位数,减去1 . 输出答案。

这是我的代码:

1  main = do
2      putStrLn "enter a non-negative integer: "
3      input <- getLine
4      let i = (read input :: Int)
5      print ((((i * 5) + 6) * 4 + 9) * 5)/100-1

在这里,我试图通过将其除以 100 来截断最后两位数字,因为这适用于其他语言。 但是,它给了我这个错误,我不确定这意味着什么:

$ runhaskell Computations.hs

Computations.hs:5:5: error:
    • No instance for (Fractional (IO ())) arising from a use of ‘/’
    • In the first argument of ‘(-)’, namely
        ‘print ((((x * 5) + 6) * 4 + 9) * 5) / 100’
      In a stmt of a 'do' block:
        print ((((x * 5) + 6) * 4 + 9) * 5) / 100 - 1
      In the expression:
        do { putStrLn "enter a non-negative integer: ";
             input1 <- getLine;
             let x = (read input1 :: Int);
             print ((((x * 5) + 6) * 4 + 9) * 5) / 100 - 1 }

Computations.hs:5:5: error:
    • No instance for (Num (IO ())) arising from a use of ‘-’
    • In a stmt of a 'do' block:
        print ((((x * 5) + 6) * 4 + 9) * 5) / 100 - 1
      In the expression:
        do { putStrLn "enter a non-negative integer: ";
             input1 <- getLine;
             let x = (read input1 :: Int);
             print ((((x * 5) + 6) * 4 + 9) * 5) / 100 - 1 }
      In an equation for ‘main’:
          main
            = do { putStrLn "enter a non-negative integer: ";
                   input1 <- getLine;
                   let x = ...;
                   .... }

那么,谁能解释一下这个错误是什么意思?

还有比除数分割更好的解决方案吗?

如何删除任意位置的数字?比如去掉一个整数的第一个、第二个和第六个数字?

ps:如果输入正确,输入和输出应该匹配。

更新:我已将“/”更改为“div”,它给了我这个:

Computations.hs:5:12: error:
    • Couldn't match expected type ‘(Integer -> Integer -> Integer)
                                    -> Integer -> Integer’
                  with actual type ‘Int’
    • The function ‘(((i * 5) + 6) * 4 + 9) * 5’
      is applied to two arguments,
      but its type ‘Int’ has none
      In the first argument of ‘(-)’, namely
        ‘((((i * 5) + 6) * 4 + 9) * 5) div 100’
      In the first argument of ‘print’, namely
        ‘(((((i * 5) + 6) * 4 + 9) * 5) div 100 - 1)’

这部分很奇怪:“函数'(((i * 5) + 6) * 4 + 9) * 5'应用于两个参数”,为什么haskell将其解释为函数?

【问题讨论】:

  • 使用div,而不是/
  • 整数除法是div,而不是/
  • @chepner,如果你省略了所述的前置条件,正确的除法运算将是quot,而不是div
  • 如果你想像运算符一样使用div,你必须把它放在反引号中。
  • 仅供参考,您可以使用以下(imo 更容易理解)代码:transform = (subtract 1) . (`quot` 100) . (*5) . (+9) . (*4) . (+6) . (*5),尽管回答“有没有比除数分割更好的解决方案?”在我的answer to your other question 中已经给出,所以这里可能不需要重复。

标签: haskell


【解决方案1】:

谁能解释错误的含义?

第一行的优先级是关闭的——中缀函数(如/)的优先级通常高于普通函数,因此print (...) / 100 等价于(print ...) / 100,这显然是有问题的。您可以将所有内容括在括号中,或使用$ 函数:

print $ ((((i * 5) + 6) * 4 + 9) * 5) / 100 - 1

现在您已将 i 限制为 Int,这仍然会产生错误:/ 仅定义为 Fractional 类型类的实例,而 Int 不是。您需要整数除法,divquot,它们仅在 Integrals(其中 Int 是一个实例)上运行,并根据需要执行截断:

print $ ((((i * 5) + 6) * 4 + 9) * 5) `div` 100 - 1

注意反引号 (`),它允许在中缀中使用普通函数。你可以这样写:

print $ (div ((((i * 5) + 6) * 4 + 9) * 5) 100) - 1

但是括号让事情变得非常难以阅读。


有没有比除数截断更好的解决方案?

一般情况下可能不会,但as mentioned on your other question,这个特殊的等式总是会给你与你的输入相同的结果,所以你可以写:

main = getLine >>= print

如何删除任意位置的数字?

转换为字符串并删除字符可能是您最好的选择。像下面这样的东西会起作用,尽管它可能有点密集:

removeDigits :: [Int] -> Int -> Int
removeDigits indices x = read . reverse . filterIndices indices . reverse . show $ x

filterIndices :: [Int] -> [a] -> [a]
filterIndices inds elems = map snd . filter ((`notElem` inds) . fst) . zip [1..] $ elems

请注意,这会将最后一个数字视为“第一个”数字 - 用它来引用数字更自然一些。


现有代码的一种(在我看来)更易于阅读的表示是:

transform = (subtract 1) . (`quot` 100) . (*5) . (+9) . (*4) . (+6) . (*5)

使用这种编写方式,组合会覆盖算术优先法则,让我们以读取方式编写它(“乘以 5,加 6,乘以 4,...”)。我们必须使用subtract 1,因为-1 被解释为字面值-1,而不是一元函数。

【讨论】:

    【解决方案2】:

    删除任意位置的数字是一个有趣的问题。这可能是最容易做到的,方法是转换为字符串并执行字符串操作,然后作为 Int 回读。由于Int 实现了ShowRead,你可以这样做:

    type Digit = Int
    
    removeDigits :: [Digit] -> Int -> Int
    removeDigits digits = read . go 1 . show
      where
      go _ []     = []
      go i (c:cs) | i `elem` digits = go cs (i+1)
                  | otherwise       = c : go cs (i+1)
    -- N.B. I chose 1-indexing here instead of 0-indexing because of your word choice
    -- "remove the first, second, and sixth digits" maps naturally to [1, 2, 6],
    -- though programmers may find that off-putting. YMMV.
    

    removeDigits这里可以改写为

    read [c | (i, c) <- zip [1..] (show n), i `notElem` digits]
    

    【讨论】:

    • 你能看看我最后发布的最后一个问题吗?谢谢。
    • @ChristianTemple 这是因为div 不是中缀函数,所以编译器会被优先级混淆。正如 Chepner 所说,使用 `div` 将解决此问题。但是,正如您在上一个问题中被告知的那样,您应该发布新问题,而不是编辑现有问题。
    猜你喜欢
    • 2017-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-20
    • 2016-04-03
    • 1970-01-01
    相关资源
    最近更新 更多