Haskell:一直在写一个复制'elem'的函数`

Haskell:一直在写一个复制'elem'的函数`,haskell,pattern-matching,list-comprehension,Haskell,Pattern Matching,List Comprehension,在haskell的第一堂课中,我们给出了一系列的问题。其中之一是当列表中存在n个数字时返回True,否则返回False。我成功地得到了我认为是一半的东西,但是我得到了不同的编译错误,我非常沮丧,因为我甚至可以理解它们的意思 到目前为止,我已经做了以下工作 // No problem with this function matches :: Int -> [Int] -> [Int] // This function is to return the matches matc

在haskell的第一堂课中,我们给出了一系列的问题。其中之一是当列表中存在n个数字时返回True,否则返回False。我成功地得到了我认为是一半的东西,但是我得到了不同的编译错误,我非常沮丧,因为我甚至可以理解它们的意思

到目前为止,我已经做了以下工作

// No problem with this function
matches :: Int -> [Int] -> [Int]    // This function is to return the matches 
matches x y = [a | a <-y, a==x]     // ie. main> 1 [1,3,5,7,1,4] outputs [1,1]

// Here am stuck
myelem :: Int -> [Int] -> Bool
myelem x [] = False
myelem x (y:ys)
 | x == y = y : x myelem ys       // Am not sure about recursion as 
                                  // we have not yet covered
//此函数没有问题
matches::Int->[Int]->[Int]//此函数用于返回匹配项
匹配xy=[a | a1[1,3,5,7,1,4]输出[1,1]
//我被卡住了
迈勒姆::Int->[Int]->Bool
myelem x[]=False
迈勒姆x(y:ys)
|x==y=y:x myelem ys//我不确定递归是否为
//我们还没有涵盖
显然,这是针对一个类,所以请不要发布答案。但也许有几个例子可以帮助我解释Haskell的工作原理以及如何解决问题。任何指针都将受到极大的赞赏


解决方案

matches :: Int -> [Int] -> [Int]
matches x y = [a | a <-y, a==x]

myelem :: Int -> [Int] -> Bool
myelem x [] = False
myelem x (y:ys)
 | x == y = True
 | otherwise = myelem x (ys)
匹配::Int->[Int]->[Int]
匹配xy=[a | a[Int]>Bool
myelem x[]=False
迈勒姆x(y:ys)
|x==y=True
|否则=myelem x(ys)

干杯,伙计们,事实上你们已经非常接近正确的答案了。不过,我看到了两个主要问题。一个是,在最后一行代码中对
myelem
的调用需要加上反引号,使其成为中缀(
x`myelem`ys
),或者是一个没有反引号的前缀调用(
myelem x ys
)。此外,您不希望在递归调用的结果前面加上
y
。实际上,您不需要在第二个模式上加上条件:只需考虑MyLem x(y:ys)是什么应该使用简单的布尔运算和已有的递归调用返回。

您尝试在最后一行包含一个
Int
和一个
Bool
,请三思

您从
myelem
中永远不会返回
True
;有时它是合适的


一旦这些问题得到解决,代码就会工作。

问题出现在您的上一个等式中:

myelem x (y:ys)
 | x == y = y : x myelem ys
这里有两个问题:

  • 如果您想使用
    myelem
    作为中缀运算符,则必须将其用倒钩环绕,如下所示:

    x `myelem` ys
    
  • 考虑到这就是你的意思,等式的右侧不会进行类型检查;列表构造函数
    (:)
    要求其第二个参数是一个列表,而不是
    Bool
    。此外,
    (:)
    构造一个列表,
    myelem
    应该返回一个
    Bool


  • 想想你要做什么。如果
    x==y
    ,你只想返回
    True
    ,对吗?
    否则,你想返回检查列表其余部分的结果(
    ys
    )。希望有帮助。

    请注意,您还可以根据
    匹配项定义
    myelem
    函数

    • 如果项目不在列表中,匹配项将返回什么
    • 如果项目在列表中一次、两次或多次,匹配项将返回什么
    • 您是否关心第二种情况下的整个返回值?(提示:否)

    您还可以使用以下函数的组合编写函数(使用以下函数至少有两种方法):

    从列表中删除元素,除非它们满足某些条件集

    null :: [a] -> Bool
    
    返回列表是否为空

    not :: Bool -> Bool
    
    这是逻辑否定

    or :: [Bool] -> Bool
    
    如果布尔列表包含一个或多个真值,则返回真


    显然,你已经解决了你的问题,但它可能会帮助你探索做同样事情的其他方法。

    @pelotom,@Jeremiah Willcock,@9000:谢谢这么多人,我只是发现将我的推理从命令式转换为声明式非常有挑战性
    执行时,它实际上是从列表中删除元素直到为空,还是只是计算列表中的剩余元素直到没有剩余?@Carlos:在Haskell这样的纯函数语言中,函数永远不能“删除”任何东西,因为这都是一种副作用,违反了纯粹性。为了了解函数列表是如何工作的,可以将它以嵌套的形式写出来:
    [1,2,3,4]
    实际上是
    1:(2:(3:[]))
    。换句话说,这个列表由另一个列表前面的
    1
    组成,
    2:(3:[])
    ,它又由另一个列表前面的
    2组成,依此类推。每个内部列表都“不知道”引用它的外部列表。@Carlos:例如,
    让xs=[1,2,3]在(4:xs,5:xs)
    中,
    …这会产生一对列表,
    ([4,1,2,3],[5,1,2,3])
    ,它们共享同一个内部列表
    xs 1,2,3]
    。作用于列表的递归函数反映了这种嵌套形式。它们在类似于
    x:xs
    的列表上进行模式匹配,对
    x
    执行操作,在内部列表
    xs
    上递归,依此类推,直到在
    []处触底
    。模式匹配不会改变任何东西,它只是简单地将列表分析为其组成部分。@pelotom:哇,伙计,非常感谢你对我的问题所做的大量解释、时间和努力。祝你好运。每当你有一个函数每次查看列表中的项目并吐出一些东西时,
    foldr通常是一个很好的方法。我建议您重新编写函数,因为这是一个很好的练习,有助于您熟悉Haskell和函数编程思想。
    
    or :: [Bool] -> Bool