开发者

How can I make a function that finds the common elements of two strings?

I want to learn how to create functions using mainly head and tail. What I need to know is the protocol or presentation of elements, how to identify the elements, and how to define the function. For example, I am practicing how to write a simple function to find the common elements of two strings. Like this:

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

where s1 and s2 are strings. But I cannot l开发者_C百科oad the modules because I get the following error message: "parse error. possible incorrect identation."


Edit: julia: Inevitably, what looks to be the same answer, from hammar appeared while writing, but maybe there is some helpful difference.

julia, as larsmans says, one problem is that you are not capitalizing the names of types and their constructors. The definition of Bool is:

data Bool = True | False

the words on both sides are capitalized; Bool is the name of the type, True and False are the constructors we match on when dividing cases. By contrast, if the new terms we define are functions and other values, we use lower case. Suppose I want to define not :: Bool -> Bool, well there are two cases:

not True = False
not False = True

with or :: Bool -> Bool -> Bool there are four cases, but we can shorten things.

or False False = False
or _ _         = True

So here, not and or are both introduced with in lower case. Now to get to your problem, the first thing to note is that the type signature and the first two cases,

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

don't really correspond to your specification, which is to find the common elements. That would have the signature

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

If we repair the first two lines to match that ambition we get

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

then, following the idea of your third case we can spare ourselves the use of head and tail if we note that in the case in question neither term will be constructed as [] but rather with :, so the case is, say:

commonElts (s:ss) (t:ts) 

Your idea was to check whether s was in the second list, and then include it in a list that is built up by using commonElts on the remaining bit, ss. There are several ways of going about this, I will use if, following your example. Note that Haskell's if...then.. is always if ... then --- else ---; the first blank is the boolean test, the other two blanks can be of any type as long as it is the same, thus we usually line them up:

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

Note. though, that elem s (t:ts) is already a Bool, True or False, so we don't need to add == True. Furthermore, we don't actually use the division of the second list into t and ts, so we can just call it ts or s2 as you did. Thus the complete definition is:

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

If an element appears more than once in the first list, it will appear more than once in the 'common element' list; we could resolve this with a further distinction of cases.

Edit: note that a very similar function can be defined with a 'list comprehension':

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


Indentation matters in Haskell. You should align the clauses for commonElt:

commonElt [] _ = true
commonElt _ [] = false
commonElt s1 s2 ...

Then realize that the boolean values are called True and False; Haskell is case sensitive.


You have a lot of errors here, and it's not clear exactly what your function should do, but here's an attempt to make some sense of it:

First, the lines definining commonElt should not be indented. Also, Bool, True and False are written with a leading upper case letter as they are constructors (Bool is a type constructor, True and False are data constructors).

Secondly, you don't use if in a guard like that. Just write the conditional on its own between the | and the =. Also, == True is uneccessary, and I think you meant to use elem, not elm.

The rest, while syntactically valid, does not type check or make much sense. show returns a String which cannot be used with (&&) because it only works on booleans (its type is 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

At this point it's not clear to me what you're trying to do, but as you said in your problem statement that you were trying to find the common elements of two lists, I think you want something like this:

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

Instead of returning a Bool, we gather up a list of the elements in s1 that are also in s2 using the (:) operator which builds a list out of a head element and a tail list.

Of couse, this could be written more succinctly using higher order functions:

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

This function already exists in the Data.List module and is called intersect.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜