如果某个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
的一个元素与函数进行比较。
答案 0 :(得分:15)
您想要的示例用法是
ghci>exists (>2) [1,2,3]
True
停止。霍格时间。 (< ------这应该是Haskell的座右铭)
你想要一个带有两个参数的函数(“存在”)。第一个是一元函数(a -> Bool)
,第二个是列表[a]
。期望的结果是Bool
Hoogling that type signature,(a -> Bool) -> [a] -> Bool
,热门匹配为any
,all
和find
。正如Andrew所指出的那样,any
就像“存在”函数一样。
作为旁注,我的第一个想法是使用find
,它返回Maybe a
,然后模式匹配。如果它返回Nothing
,则结果为False
,否则为True
。
另外注意,actual implementation只是any p = or . map p
。
第三方可能是您实际问题的答案。如何定义map
?霍尔格再次成为你的朋友。搜索方法的名称,您可以找到链接到源的页面。我建议您为map
和or
执行此操作,但此处仅显示map
。
map _ [] = []
map f (x:xs) = f x : map f xs
这是递归列表的基本方法。 recursiveCall f (x:xs) = f x : recursiveCall f xs
但如果可以使用map
,filter
或foldl
/ 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
子句还应该在列表的其余部分返回Bool
:exists
的结果。