如何创建一个找到两个字符串的公共元素的函数?

时间:2011-06-17 17:27:52

标签: haskell

我想学习如何主要使用head和tail创建函数。我需要知道的是元素的协议或表示,如何识别元素以及如何定义函数。例如,我正在练习如何编写一个简单的函数来查找两个字符串的公共元素。像这样:

commonElt :: (Eq a)=> [a]->[a]-> bool

                commonElt [] _ = true
                commonElt _ [] = false
commonElt s1 s2 |if elm (head s1)s2 == true then show head s1 && commonElt(tail s1)s2
                |otherwise = commonElt(tail s1) s2

其中s1s2是字符串。但是我无法加载模块,因为我收到以下错误消息:“解析错误。可能是错误的识别。”

3 个答案:

答案 0 :(得分:4)

修改:julia:不可避免的是,在写作时hammar出现了同样的答案,但也许有一些有用的区别。

julia,正如larsmans所说,一个问题是你没有大写类型及其构造函数的名称。 Bool的定义是:

data Bool = True | False

双方的话都是大写的; Bool是类型的名称,TrueFalse是我们在分割案例时匹配的构造函数。相比之下,如果我们定义的新术语是函数和其他值,我们使用小写。假设我想定义not :: Bool -> Bool,有两种情况:

not True = False
not False = True

or :: Bool -> Bool -> Bool有四种情况,但我们可以缩短内容。

or False False = False
or _ _         = True

所以在这里,notor都以小写字母引入。现在要解决您的问题,首先要注意的是类型签名和前两种情况,

commonElt :: (Eq a) => [a] -> [a] -> Bool
commonElt [] _ = True
commonElt _ [] = False

并不真正符合您的规范,即找到共同的元素。那将有签名

commonElts :: (Eq a) => [a] -> [a] -> [a]

如果我们修复前两行以符合我们的抱负

commonElts [] _ = []
commonElts _ [] = []

然后,根据您的第三个案例的想法,如果我们注意到在相关案例中,任何一个术语都不会被构造为head,那么我们可以免费使用tail[]。而是:,所以情况就是这样说:

commonElts (s:ss) (t:ts) 

您的想法是检查s是否在第二个列表中,然后将其包含在使用commonElts在剩余位ss上构建的列表中。有几种方法可以解决这个问题,我将按照您的示例使用if。请注意,Haskell的if...then..始终为if ... then --- else ---;第一个空白是布尔测试,其他两个空格可以是任何类型,只要它是相同的,因此我们通常将它们排成一行:

commonElts (s:ss) (t:ts) = 
     if elem s (t:ts) == True then s : commonElts ss (t:ts)
                              else commonElts ss (t:ts)

请注意。但是,elem s (t:ts)已经是Bool,无论是真还是假,所以我们不需要添加== True。此外,我们实际上并未将第二个列表划分为tts,因此我们可以像您一样将其称为tss2。因此,完整的定义是:

 commonElts [] _ = []
 commonElts _ [] = []
 commonElts (s:s1) s2 = 
    if elem s s2 then s : commonElts s1 s2
                 else commonElts s1 s2

如果一个元素在第一个列表中出现多次,它将在“common element”列表中出现多次;我们可以通过进一步区分案例来解决这个问题。

编辑:请注意,可以使用'list comprehension'定义一个非常相似的函数:

common xs ys = [ x | x <- xs , y <- ys, x == y]

答案 1 :(得分:3)

Haskell中的缩进很重要。您应该对齐commonElt

的子句
commonElt [] _ = true
commonElt _ [] = false
commonElt s1 s2 ...

然后意识到布尔值被称为TrueFalse; Haskell区分大小写。

答案 2 :(得分:3)

你在这里遇到很多错误,并不清楚你的功能究竟应该做些什么,但这是尝试对它有所了解:

首先,定义commonElt的行不应缩进。此外,BoolTrueFalse使用前导大写字母编写,因为它们是构造函数(Bool是类型构造函数,True和{{ 1}}是数据构造函数)。

其次,你不要在这样的警卫中使用False。只需在if|之间自行编写条件。此外,=是不必要的,我认为您打算使用== True,而不是elem

其余的,虽然在语法上有效,但不会检查或有意义。 elm返回showString不能与(&&)一起使用,因为它仅适用于布尔值(类型为Bool -> Bool -> Bool)。

commonElt :: (Eq a) => [a] -> [a] -> Bool
commonElt [] _ = True
commonElt _ [] = False
commonElt s1 s2 | elem (head s1) s2 = show (head s1) && commonElt (tail s1) s2
                | otherwise = commonElt (tail s1) s2

此时我不清楚你要做什么,但正如你在问题陈述中所说的那样,你试图找到两个列表的共同元素,我想你想要这样的东西:

commonElt :: (Eq a) => [a] -> [a] -> [a]
commonElt [] _  = []
commonElt s1 s2 | elem (head s1) s2 = head s1 : commonElt (tail s1) s2
                | otherwise = commonElt (tail s1) s2

我们不是返回Bool,而是使用s1运算符从s2中收集(:)中的元素列表,该运算符构建了一个列表。头元素和尾部列表。

当然,使用更高阶函数可以更简洁地写出来:

commonElt s1 s2 = filter (`elem` s2) s1

此功能已存在于Data.List模块中,名为intersect