【问题标题】:Haskell Integer Odd Digits CheckerHaskell 整数奇数检查器
【发布时间】:2017-06-12 14:54:45
【问题描述】:

我似乎被困在一个问题上,不知道如何解决它,也不知道我当前的代码做错了什么。

我必须编写一个名为oddDigits 的函数,它接受一个整数参数并返回一个布尔结果。当且仅当参数是奇数位数的正整数时,它才应该返回 True。如果参数为零或负数,函数应停止并显示错误消息。

另外,不能将参数转换为字符串。必须使用递归。 我有一种感觉,每个数字都可以递归地存储在一个列表中,然后列表的长度可以确定答案。

到目前为止,我有这个:

oddDigits :: Integer -> Bool 

lst = [] 

oddDigits x 
    | (x < 0) || (x == 0) = error 
    | x `mod` 10 ++ lst ++ oddDigits(x `div` 10) 
    | length(lst) `mod` 2 /= 0 = True
    | otherwise = False 

抱歉,如果代码看起来很糟糕。我是 Haskell 的新手,仍在学习。我到底做错了什么,我该如何纠正?

【问题讨论】:

    标签: function haskell recursion


    【解决方案1】:

    首先,这似乎是一件很奇怪的事情。也许你做错的是考虑这个问题......

    但如果你坚持,你想知道具有奇数位数的整数的属性...哦,好吧。有很多可以改进的地方。对于初学者,(x &lt; 0) || (x == 0) 不需要括号 - &lt;==(中缀 4)比 || 绑定得更紧密。如果您对此不确定,可以随时询问 GHCi:

    Prelude> :i ==
    class Eq a where
      (==) :: a -> a -> Bool
      ...
        -- Defined in ‘GHC.Classes’
    infix 4 ==
    Prelude> :i ||
    (||) :: Bool -> Bool -> Bool    -- Defined in ‘GHC.Classes’
    infixr 2 ||
    

    但是在这里您无论如何都不需要||,因为有一个专门的小于或等于运算符。因此你可以写

    oddDigits x 
      | x <= 0  = error "bla bla"
      | ...
    

    然后,you can 将数字“转换”为字符串。转换为字符串通常是一件非常令人不快的事情,因为它会将所有结构、类型检查等抛到窗外;但是“位数”基本上字符串的属性(十进制扩展),而不是数字本身,所以这对于这个特定的任务来说并不是完全不明智的。这会起作用:

    oddDigits x 
     | x <= 0                      = error "blearg"
     | length (show x)`mod`2 /= 0  = True
     | otherwise                   = False 
    

    但是,这有点冗余部门冗余。您正在检查某事是否为True,然后给出True 作为结果......为什么不把它放在一个子句中:

    oddDigits x 
     | x <= 0     = error "blearg"
     | otherwise  = length (show x)`mod`2 /= 0
    

    这实际上可能是最好的实现。

    对于任何适当,明智的任务,我不建议走字符串路线。递归更好。下面是它的样子:

    oddDigits 1 = True
    oddDigits x 
     | x <= 0     = error "blearg"
     | otherwise  = not . oddDigits $ x`div`10
    

    【讨论】:

      【解决方案2】:

      转换为数字列表然后查找列表长度的一般方法没有问题。真正出错的地方是试图将所有内容都塞进一个函数中。正如您亲身发现的那样,调试起来非常困难。函数式编程最适合非常个小函数。

      如果您使用 digs 函数(如 this answer 中的函数)分离出将整数转换为数字列表的职责,则算法的其余部分将简化为:

      oddDigits x | x <= 0 = error
      oddDigits x = odd . length $ digs x
      

      【讨论】:

        【解决方案3】:

        leftaroundabout 的最终答案非常好,但是对于像 2,3 和 23 这样的数字它会失败。这是一个修复。

        oddDigits x 
          | x <= 0     = error "blearg"
          | x < 10     = True
          | otherwise  = not . oddDigits $ x`div`10
        

        它比我最初的答案优雅得多,如下所示。我将它包括在内是为了介绍一个常见的功能范式,即问题的工作者/包装器转换。在这里,包装器提供接口并将工作传递给另一个函数。请注意,现在只需要进行一次否定性检查。

        oddDigits :: Integer -> Bool
        oddDigits x
           | x <= 0 = False
           | otherwise = oddDigits' True x
        
        oddDigits' :: Bool -> Integer -> Bool
        oddDigits' t x
           | x < 10 = t
           | otherwise = oddDigits' (not t) $ x `div` 10
        

        oddDigits' 带有一段内部数据,初始 Bool。我的第一个想法是让 Bool 成为一个数字累加器,计算位数。在这种情况下,需要提供一个“解包器”,在这种情况下是标准的“奇数”函数:

        oddDigits x
           | x <= 0 = False
           | otherwise = odd . oddDigits'' 1  $  x
        

        在哪里oddDigits'' :: Integer -&gt; Integer -&gt; Integer

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-06-09
          • 1970-01-01
          • 2012-04-15
          • 1970-01-01
          • 1970-01-01
          • 2010-09-14
          • 1970-01-01
          相关资源
          最近更新 更多