Yuki1112
Yuki1112

Reputation: 365

Haskell Rotate String with exeptions

I'm new to Haskell and I'm trying to shift a character by one to the right and that the last character will always be first, and that it would return a string.

For example: shiftString "abcd" = "dabc" but the compiler doesn't agree with me, can anybody help me fix this?

shiftString :: String -> String
shiftString x = take (length x) $ iterate rot1 x
        where rot1 = drop 1 x ++ take 1 x

Also, I want to check after this on two Strings and returns True if one of them is a result of applying shiftString one or more times, how can I use this to do that? as in:

isShifted :: String -> String -> Bool

Upvotes: 0

Views: 109

Answers (2)

mohamad Jamal
mohamad Jamal

Reputation: 28

-- shiftString "abcd"   == "dabc"
-- shiftString "hello"  == "ohell"
-- shiftString "orange" == "eorang"

shiftString :: [a] -> [a]
shiftString lst = [ head (reverse lst)] ++ (init lst)


-- Test Cases
-- isShifted "abcdefg" "gabcdef"   == True
-- isShifted "hello" "ohell"       == True
-- isShifted "orange" "eorange"    == False



isShifted :: String -> String -> Bool
isShifted str1 str2                  
        | shiftString str1  == str2 = True
        | otherwise             = False

Upvotes: 0

Random Dev
Random Dev

Reputation: 52290

A String in Haskell is just a list of Chars - so you can do this using simple pattern-matching:

shiftString' :: String -> String
shiftString' (firstChar:restChars) = restChars ++ [firstChar]
shiftString' [] = []

now if you try this it'll do the opposite of what you want - but there is a trick: we reverse the string twice:

shiftString :: String -> String
shiftString = reverse . shiftString' . reverse

that should do the trick


fix yours:

I think you only need the rot1 (it does the same as my shiftString') together with the reverse trick from above

Or - to fix yours more:

I guess you tried with the iterate to rot1 more times and then drop the rest - that works too:

shiftS cs = head $ drop (length cs - 1) $ iterate rot1 cs

rot1 cs = drop 1 cs ++ take 1 cs

note that iterate gives you a list of strings (with more and more rotations) - I drop the first n-1 (where n = length of the input) which gives me a list again (one type-error on your version) and take the head of that because I only want the first String in this list.


for your isShifted you can reuse the iterate with rot1 (no need to care about order) - this time take length cs from this and then check if your other input is an element of this list:

isShifted cs cs' = cs `elem` take (length cs) (iterate rot1 cs')

Example:

Prelude> isShifted "abcd" "cdab"                                           
True                                                                       
Prelude> isShifted "abdc" "cdab"                                           
False                                                                      

note that you cannot just use iterate rot1 cs' without the take - think about it and then try what happens ;) (hint: it'll work when your inputs are shifted - but you'll get into trouble if they are not - why?)

Upvotes: 1

Related Questions