【问题标题】:Return a boolean value from a list comprehension从列表推导中返回一个布尔值
【发布时间】:2011-09-23 03:18:17
【问题描述】:

我是 Haskell 的新手,正在为我正在学习的函数式编程课程解决一些教程问题。有一个问题我完全被难住了。

定义一个函数,返回给定字符串是否包含所有数值(即“123”=> True,“1a3”=> False)。该函数必须使用列表推导式。

是最后一部分让我死心。没有列表理解很容易编写。使用谓词编写列表推导式也很容易,以确保您只将数字字符放入新列表中。

isNum  =  [ x | x <- xs, x `elem` ['0'..'9'] ]

但是我不确定如何将新列表与原始列表进行比较以检查是否相等,因为这是整个函数定义。

【问题讨论】:

    标签: haskell


    【解决方案1】:

    提示:使用列表推导,而不仅仅是列表推导。

    是否有一些您可以生成的列表,然后运行一些进一步的处理以获得您需要的答案?

    【讨论】:

      【解决方案2】:

      如果我是你,我会检查列表 [x | x &lt;- xs, not (elem x ['0'..'9'])] 是否为空。

      【讨论】:

        【解决方案3】:

        对于我首先想到的解决方案,我能想到的小提示:

        x elem ['0'..'9'] 对此有用,但不能作为守卫。

        【讨论】:

          【解决方案4】:

          我猜这个作业需要一个列表理解,但是这样做的惯用方法是:

          import Data.Char
          isNum = all isDigit
          

          开个玩笑,如果你想跳出框框思考,你可以加入列表推导式,但忽略它!

          isNum =
              let unnecessaryListComprehension = [x | x <- [0..]]
              in all isDigit
          

          或使用Monoid

          import Data.Monoid
          isNum xs = getAll $ mconcat [All $ isDigit x | x <- xs]
          

          【讨论】:

            【解决方案5】:

            这是作业吗?

            由于列表推导将只包含数字字符,如果有任何非数字元素,结果列表会更短。

            另一种方法是输入isNum xs = [ elem x ['0'..'9'] | x &lt;- xs ]。然后你有一个布尔值列表,告诉你每个字符是否是一个数字。您可以使用 Prelude 函数来告诉您是否所有值都是 True

            编辑:更有效的是,还有一个 Prelude 函数可以告诉您是否有任何元素是 False,表示非数字元素。

            【讨论】:

            • 啊,这很有见地。我缺少的是你总是可以将一个函数包装在另一个函数中的事实(呃,它是函数式编程)。所以我可以做 isNum = [ x | x elem ['0'..'9'] ] == xs 甚至更好 isNum = length [ x | x elem ['0'..'9'] ] == 长度 xs
            • @August。您的解决方案有效,但它不如使用 Booleans 的列表有效,因为您正在比较两个列表的长度,它遍历整个列表,而不是(部分)遍历一个列表的布尔函数。
            • 比较列表是否相等比比较长度更有效。
            • @vivian,仅在答案为False的情况下。
            【解决方案6】:

            虽然有一个答案标记为正确,但我认为完整的实现会是这样的:

            isNum xs = foldr (&&) True [x `elem`['0'..'9'] | x <- xs] -- or
            
            isNum xs = foldl (&&) True [x `elem`['0'..'9'] | x <- xs] -- or
            
            isNum xs = and [x `elem`['0'..'9'] | x <- xs] -- Thanks for the comment of hammar
            
            isNum "123" -- returns True
            isNum "1a3" -- returns False
            

            【讨论】:

            • 此折叠already exists in the Preludeand = foldr (&amp;&amp;) True.
            • 我刚刚查找了 foldl/foldr。我不熟悉这些功能,我正在尝试了解它是如何工作的。所以列表推导返回一个布尔值列表。然后调用 foldl/foldr (&amp;&amp;) True 返回一个函数,该函数返回对 True 和列表的第一项执行的逻辑和运算的结果。然后在列表的第二项上调用返回的函数,依此类推。所以返回的最终结果将只是 True 或 False。那是对的吗?这也将比我发布的解决方案更有效吗?感谢您的帮助
            • 你说得对 foldl/foldr (&&) True,最终结果将是 True 或 False,因为在 Haskell 中逻辑运算符是惰性的,如果遇到 False,它将立即返回。但是,如果所有的值都是 True,那么它将需要走到最后。它的效率可能与您检查列表相等性的效率相同。
            【解决方案7】:

            isNum xs = null [ x | x notElem ['0'..'9'] ]

            只需检查列表是否为空..

            【讨论】:

              【解决方案8】:

              你可以使用这个偏函数:

              isNum :: [Char] -> Bool
              isNum = foldl (\acc x -> acc && x `elem` ['0'..'9']) True
              

              例子:

              Prelude> isNum "111"
              True
              Prelude> isNum "111aaa"
              False
              

              【讨论】:

                猜你喜欢
                • 2019-04-15
                • 1970-01-01
                • 2021-03-21
                • 1970-01-01
                • 2014-05-16
                • 1970-01-01
                • 1970-01-01
                • 2021-07-31
                • 1970-01-01
                相关资源
                最近更新 更多