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

时间:2011-01-23 22:56:37

标签: haskell

如果某个f的{​​{1}}为真,那么如何编写一个带谓词xx和列表fx的函数并重新生成?

例如:

x∈xs

这是我写的函数:

 ghci>exists (>2) [1,2,3]
     True

我知道这不对,但我不知道为什么。我是否需要首先编写此谓词函数 exists :: (t->Bool)->[t]->Bool exists f a []=error exists f a (x:xs) |if x∈f a =True |otherwise= x:f a xs ,然后在函数f中使用它。因为我真的不知道如何将列表exists的一个元素与函数进行比较。

5 个答案:

答案 0 :(得分:15)

您想要的示例用法是

ghci>exists (>2) [1,2,3]
True

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

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

Hoogling that type signature(a -> Bool) -> [a] -> Bool,热门匹配为anyallfind。正如Andrew所指出的那样,any就像“存在”函数一样。

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

另外注意,actual implementation只是any p = or . map p

第三方可能是您实际问题的答案。如何定义map?霍尔格再次成为你的朋友。搜索方法的名称,您可以找到链接到源的页面。我建议您为mapor执行此操作,但此处仅显示map

map _ []     = []
map f (x:xs) = f x : map f xs

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

答案 1 :(得分: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

我们看到您的类型是

exists :: (t -> Bool) -> [t] -> Bool

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

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

exists f a [] = error

此功能突然有三个参数。 f和空列表构造函数[]看起来没问题,但类型规范中未提及a。因此,我们将其删除:

exists f [] = error

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

到下一行,

exists f a (x:xs)
      |if x∈f a  =True
      |otherwise= x:f a xs

我们了解到a必须遵循类型规范,所以让我们修剪它。既然我们现在已经对a产生了一种自然的厌恶,为什么不在它发生的任何地方修剪它。此外,由于if会产生语法错误,所以我们也要摆脱它:

exists f (x:xs)
      | x∈f    = True
      | otherwise = x:f xs

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

所以我们将注意力转向最后一行。 otherwise表示警卫f x未返回True。因此,x不满足谓词,因此我们必须搜索列表的其余部分。

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

您缺少的关键是我们此时需要递归。我们需要以某种方式搜索列表的尾部xs - 并且递归意味着调用尾部的exists函数。

您的一般跟踪是正确的,但如果不清楚,请再次询问。一个技巧可能是递归递归案例的类型:“我必须提供exists以使其返回Bool值?”。

答案 2 :(得分:4)

我认为您想要的功能已经存在 - any

Prelude> :t any
any :: (a -> Bool) -> [a] -> Bool
Prelude> any (<3) [1, 2, 3, 4]
True
Prelude> any (<3) [3, 4, 5, 6]
False

然后,根据你的问题的精神 - 不仅要获得一个有效的功能,而且要弄清楚它是如何完成的 - 我们可以在前奏中查找定义:

any p xs = or (map p xs)

我们map列表中的功能以获取新的[Bool]列表,然后与or核对,看看其中是否有True,谢谢懒惰的评估短路:

Prelude> any (<3) [1, 2..]
True

答案 3 :(得分:2)

实际上你原来的版本离工作太远了。要修复它,请写:

exists :: (t -> Bool) -> [t] -> Bool
exists _ [] = False
exists f (x:xs)
            | f x = True
            | otherwise = exists f xs

答案 4 :(得分:0)

不要在x中使用f,而只需将f应用于x,使用f x作为if语句中的谓词。您的otherwise子句还应该在列表的其余部分返回Boolexists的结果。