代码之家  ›  专栏  ›  技术社区  ›  Christian Temple

从整数中删除数字

  •  1
  • Christian Temple  · 技术社区  · 8 年前

    我遇到了一个家庭作业问题:

    输入一个大于或等于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将其解释为函数?

    2 回复  |  直到 8 年前
        1
  •  3
  •   hnefatl    8 年前

    有人能解释一下错误的含义吗?

    第一行中的优先级是非中缀函数(如 / )通常比普通的优先级高,所以 print (...) / 100 相当于 (print ...) / 100 ,这显然是有问题的。您可以将所有内容都用括号括起来,或使用 $ 功能:

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

    现在,由于您的限制 i 成为一名 Int ,仍然会出现错误: / 仅为的实例定义 Fractional typeclass,以及 内景 不是。你想要整数除法, div 或 quot ,仅在 Integral s(其中 内景 是一个实例),并根据需要执行截断:

    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
  •  3
  •   Adam Smith    8 年前

    删除任意位置的数字是一个有趣的问题。通过转换为字符串并执行字符串操作,然后作为Int读回,这可能是最容易做到的 Int 实现两个 Show 和 Read ,您可以执行以下操作:

    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]
    
    推荐文章