使用递归或更高阶函数编写函数

Cat*_*yLu 3 haskell

如何编写一个带谓词f和列表的函数,xx如果fx对某些人来说是真的,那么它会重新出现x?xs吗?

例如:

 ghci>exists (>2) [1,2,3]
     True
Run Code Online (Sandbox Code Playgroud)

这是我写的功能:

 exists :: (t->Bool)->[t]->Bool
    exists f a []=error
    exists f a (x:xs)
                |if x?f a  =True
                |otherwise= x:f a xs
Run Code Online (Sandbox Code Playgroud)

我知道这不对,但我不知道为什么.我是否需要先编写此谓词函数f,然后在函数内部使用它exists.因为我真的不知道如何比较列表的一个元素和xs函数.

Dan*_*ton 15

您想要的示例用法是这样的

ghci>exists (>2) [1,2,3]
True
Run Code Online (Sandbox Code Playgroud)

停止.霍格时间.(<------这应该是Haskell的座右铭imho)

你想要一个带有两个参数的函数("存在").第一个是一元函数(a -> Bool),第二个是列表[a].期望的结果是aBool

Hoogling这种类型的签名,(a -> Bool) -> [a] -> Bool中,排名靠前的是any,allfind.正如安德鲁所指出的那样,any行为就像"存在"一样.

作为旁注,我的第一个想法是使用find,返回a Maybe a,然后模式匹配.如果它返回Nothing,那么结果将是False,否则True.

另一方面,实际的实施很简单any p = or . map p.

第三方可能是您实际问题的答案.怎么map定义?霍尔格再次成为你的朋友.搜索方法的名称,您可以找到链接到源的页面.我建议你这样做mapor,但将只显示map在这里.

map _ []     = []
map f (x:xs) = f x : map f xs
Run Code Online (Sandbox Code Playgroud)

这是递归列表的基本方法.recursiveCall f (x:xs) = f x : recursiveCall f xs但如果它可以用map,filterfoldl/ 编写foldr,那么你应该使用这些递归方法.(停止.Hoogle时间.搜索这些方法名称并查看来源;这非常简单.)

  • 获得+1的答案和"停止.Hoogle时间".我早上做了:-) (2认同)

I G*_*ERS 6

如果我们看看你的定义,

exists :: (t -> Bool) -> [t] -> Bool
exists f a []=error
exists f a (x:xs)
            |if x?f a  =True
            |otherwise= x:f a xs
Run Code Online (Sandbox Code Playgroud)

我们看到你的类型是

exists :: (t -> Bool) -> [t] -> Bool
Run Code Online (Sandbox Code Playgroud)

因此exists必须采用两个参数,一个类型的谓词函数(t -> Bool)和一个类型列表[t].它返回一个Bool.根据我们的规范意图,这似乎没问题.

让我们看一下你的术语的第一行:

exists f a [] = error
Run Code Online (Sandbox Code Playgroud)

这个功能突然有三个参数.该f和空列表构造[]看起来不错,但a没有在类型说明书中提到的.因此,我们将其删除:

exists f [] = error
Run Code Online (Sandbox Code Playgroud)

现在,error返回的不是布尔值.但规范说它一定是.让我们假设我们在问exists (<2) [].那么这个问题的自然答案是True或者False?或者转述,是否有任何元素x in []满足谓词f x

到下一行,

exists f a (x:xs)
      |if x?f a  =True
      |otherwise= x:f a xs
Run Code Online (Sandbox Code Playgroud)

我们了解到a必须遵循类型规范,所以让我们修剪它.既然我们现在已经变得天生不喜欢了a,为什么不在任何地方修剪它.此外,由于if会产生语法错误,我们也可以摆脱它:

exists f (x:xs)
      | x?f    = True
      | otherwise = x:f xs
Run Code Online (Sandbox Code Playgroud)

x?f没有多大意义,但f x确实.如果f x返回true,则将采用保护变量.现在,这里返回的True听起来是正确的.它表示我们在列表中找到了一个与谓词匹配的元素 - 而且x看起来可能就是这样!

所以我们把注意力转向最后一行.该otherwise方法的后卫f x并没有返回True.因此,x不满足谓词,所以我们必须搜索列表的其余部分.

右手边x : f xs是奇特的.这:意味着我们将尝试返回一个列表,但函数的返回类型是类型Bool.如果我们尝试这个,类型检查器将不会喜欢我们.此外,我们没有理由再看它x了,因为我们只是确定它不满足谓词.

你缺少的关键是我们需要递归.我们需要以xs某种方式搜索列表的尾部- 而递归意味着调用exists尾部的函数.

你的一般轨道是正确的,但如果有什么不清楚的话,再问一遍.一个技巧可能是通过递归案例的类型:"我必须exists为它提供什么来返回Bool值?".