Haskell 使用递归确定子集

Haskell 使用递归确定子集,haskell,recursion,set,subset,infinite-loop,Haskell,Recursion,Set,Subset,Infinite Loop,我试图编写一个函数子集,它包含两个列表,并确定第一个列表的元素是否出现在第二个列表中 代码编译为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 谢谢大家! subs

我试图编写一个函数
子集
,它包含两个列表,并确定第一个列表的元素是否出现在第二个列表中

代码编译为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
谢谢大家!

subset (x:xs) ys
 | elem x ys = subset (x:xs) ys
                   -- ^^^^^^ --
请注意,上面的递归调用不会更改参数!这将导致无限递归。在进行递归调用之前,您希望删除
x


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

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

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

i、 e.当第一个参数为false时,甚至不会检查第二个参数的值。

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

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

i、 e.当第一个参数为false时,第二个参数的值甚至不被检查。

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

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

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

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

也许有意思:您不需要像这样显式地在
elem x ys
上分支。您可以
subset(x:xs)ys=elem x ys&&subset{-…请参见下面的答案…-}ys
,惰性将确保递归调用只在需要时发生。可能有意思的是:您不需要像这样显式地分支
elem x ys
。您可以
subset(x:xs)ys=elem x ys&&subset{-…请参见下面的答案…-}ys
,而laziness将确保递归调用仅在需要时发生。