【问题标题】:Determine subset using recursion使用递归确定子集
【发布时间】:2019-06-27 01:41:29
【问题描述】:

我正在尝试编写一个函数subset,它接受两个列表并确定第一个列表的元素是否出现在第二个列表中。

当输入如下函数时,代码编译到 GHCi,但不运行(即卡住):

subset [1,2] [1,2]

这是我的代码:

subset :: (Eq a) => [a] -> [a] -> Bool
subset [] ys = True
subset (x:xs) ys
 | elem x ys = subset (x:xs) ys
 | otherwise =  False

谢谢!

【问题讨论】:

  • 也许感兴趣:您不需要像那样显式地在elem x ys 上进行分支。你可以subset (x:xs) ys = elem x ys && subset {- ... see answers below ... -} ys 和懒惰将确保递归调用只在需要时发生。

标签: haskell recursion set subset infinite-loop


【解决方案1】:
subset (x:xs) ys
 | elem x ys = subset (x:xs) ys
                   -- ^^^^^^ --

请注意,上面的递归调用不会改变参数!这将导致无限递归。您想在进行递归调用之前删除x

【讨论】:

    【解决方案2】:

    让我们仔细看看你的代码片段:

    subset (x:xs) ys
     | elem x ys = subset (x:xs) ys
    

    如果elem x ys 成立,这是完全合理的,你有

    subset (x:xs) ys = subset (x:xs) ys
    

    它不减少任何参数,只是重新重复相同的调用。

    因此,无限循环。

    在处理布尔值时,习惯上使用逻辑连接词,这通常会导致更简洁明了的定义:

    subset (x:xs) ys = elem x ys && subset ..... .....
    

    这就是你所需要的,因为(&&)的真值表是

        True  && x  =  x
        False && _  =  False
    

    即当第一个参数为 false 时,甚至不检查第二个参数的值。

    【讨论】:

      【解决方案3】:

      不需要显式递归;您可以使用all 来验证(`elem` ys) 是否适用于xs 中的每个值:

      subset xs ys = all (`elem` ys) xs
      

      【讨论】:

        猜你喜欢
        • 2013-10-25
        • 2019-03-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-18
        • 2011-03-21
        相关资源
        最近更新 更多