Pregunta

I need to write function, which is seeking for "Z" in string, and when this function finds it on i index, it appends i+3 Char to table.

Here is my code:

someFun :: String => String -> String -> String
someFun "" (r:rs) = (r:rs)
someFun (a:b:c:d:xs) (r:rs)
    | a == "Z" = someFun xs ((r:rs)++d)
    | otherwise = someFun (b:c:d:xs) (r:rs)

I got bunch of errors that I don't know how to fix due to my poor experience in Haskell programming.

EDIT: If input is "(C (N (Z 'p')) (A (K (Z 'p') (Z 'q')) (Z 'r')))" its output should be: ['p','q','r']

¿Fue útil?

Solución 2

It's not really clear what you're trying to do but this compiles:

someFun :: String -> String -> String
someFun "" (r:rs) = (r:rs)
someFun (a:b:c:d:xs) (r:rs)
    | a == 'Z' = someFun xs ((r:rs)++[d])
    | otherwise = someFun (b:c:d:xs) (r:rs)

The String => is for typeclass constraints, which you don't need. d is a Char while (++) is defined on lists (of Chars in this case).

Your function has incomplete pattern matches, so you could also define those, which will simplify the existing cases:

someFun :: String -> String -> String
someFun _ [] = error "Empty string"
someFun "" s = s
someFun ('Z':b:c:d:xs) s = someFun xs (s++[d])
someFun (_:b:c:d:xs) s = someFun (b:c:d:xs) s
someFun _ _ = error "String was not in the expected format"

To display it on the screen you can use putStrLn or print:

displaySomeFun :: String -> String -> IO ()
displaySomeFun s1 s2 = putStrLn (someFun s1 s2)

Otros consejos

The specification is not entirely clear, but it sounds like you want to collect all the characters which occur three places after a 'Z' in the input, so that from

"BUZZARD BAZOOKA ZOOM"

we get

"RDKM"

Without a clearer presentation of the problem, it is difficult to give precise advice. But I hope I can help you get past some of the small irritations, so that you can engage with the actual logic of the problem.

Let's start with the type. You have

someFun :: String => String -> String -> String

but left of => is the place for properties of type expressions, usually involving variables that could stand for lots of types, such as Eq a (meaning that whatever type a is, we can test equality). String is a type, not a property, so it cannot stand left of =>. Drop it. That gives

someFun  :: String -- input
         -> String -- accumulating the output (?)
         -> String -- output

It is not clear whether you really need an accumulator. Suppose you know the output for

"ZARD BAZOOKA BOOM"  -- "DKM", right?

Can you compute the output for

"ZZARD BAZOOKA BOOM"  -- "RDKM"

? Just an extra 'R' on the front, right? You're using tail recursion to do the next thing, when it is usually simpler to think about what things should be. If you know what the output is for the tail of the list, then say what the output is for the whole of the list. Why not just map input to output directly, so

someFun :: String -> String

Now, pattern matching, start with the simplest possible pattern

someFun s = undefined

Can you see enough about the input to determine the output? Clearly not. It matters whether the input is empty or has a first character. Split into two cases.

someFun ""      = undefined
someFun (c : s) = undefined   -- c is the first Char, s is the rest of the String

It also matters whether the first character is 'Z' or not. Be careful to use single quotes for Char and double quotes for String: they are different types.

someFun ""         = undefined
someFun ('Z' : s)  = undefined   -- the first Char is Z
someFun (c : s)    = undefined

In the case wit 'Z', you also want to make sure that s has at least three characters, and we care about the third, so

someFun ""                         = undefined   -- input empty
someFun ('Z' : s@(_ : _ : d : _))  = undefined   -- first is 'Z' and d is 3 later
someFun (c : s)                    = undefined   -- input nonempty

The @ is an "as pattern", allowing me to name the whole tail s and also check that it matches (_ : _ : d : _), grabbing the third character after the 'Z'.

So far, I've given no thought to the output, just what I need to see about the input. Let's figure out what the output must be. In the first case, empty input gives empty output

someFun ""                         = ""
someFun ('Z' : s@(_ : _ : d : _))  = undefined   -- first is 'Z' and d is 3 later
someFun (c : s)                    = undefined   -- input nonempty

and in the other two cases, we can assume that someFun s already tells us the output for the tail of the list, so we just need to figure out how to finish the output for the whole list. In the last line, the output for the tail is just what we want.

someFun ""                         = ""
someFun ('Z' : s@(_ : _ : d : _))  = undefined   -- first is 'Z' and d is 3 later
someFun (c : s)                    = someFun s

But in the case where we've found that d is three places after the initial 'Z', we need to make sure d is at the start of the output.

someFun ""                         = ""
someFun ('Z' : s@(_ : _ : d : _))  = d : someFun s
someFun (c : s)                    = someFun s

Just checking:

*Main> someFun "BUZZARD BAZOOKA ZOOM"
"RDKM"

The key idea is to figure out how to express the output for the whole input in terms of the output for its pieces: what it is, not what to do. Here, you can assume that the output for the tail, s is correctly computed, so you just need to figure out whether you have anything extra to return.

Lee showed how you get it to compile. There are still some things to say about: You have to provide more pattern-cases, You get an error for example if you try to run someFun "" "", or someFun "A" "ABCD"

First improvement: Change (r:rs) to rs, you never use r, so you can change it to a more general case (that will fix the error on someFun "" ""). The other thing is, that you don't pattern match on lists with one, two, or tree elements. You could add someFun _ rs = rs, so that in those cases nothing happens.

Read about head and tail.It is easier with them.And end the cycle when the length of your first list is less than 4.

someFun [] rs = rs
someFun xs rs
| (length xs) < 4 = rs
| (head xs) == 'Z' = someFun (tail xs) (rs ++ [head (tail (tail (tail xs)))])
| otherwise = someFun (tail xs) rs

You can take advantage of how failing pattern-matches work in list comprehensions and the Data.List.tails function:

import Data.List (tails)

someFun :: String -> String
someFun s = [x | 'Z':_:_:x:_ <- tails s]

The tails function gives you all tails of a list (remember that a String ist just a list of Char), e.g.:

λ: tails "Overflow"
["Overflow","verflow","erflow","rflow","flow","low","ow","w",""]

The pattern ('Z':_:_:x:_) matches any string which starts with a Z and is at least four characters in size. For each pattern match, the character which is three positions after Z is extracted.

The magical part about it is that when the pattern fails (e.g. for tails which don't start with a Z or which are too short), the element is skipped silently and doesn't contribute to the result - exactly what you seem to request.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top