Help with haskell rotate code
Ok so i know this is slightly wrong but what am i missing in it? The code is to rotate individual letters in words like:
rotate 1 "hello" "ohell"
rotate -1 "hello" "elloh"
The code i have is:
module Main where
import System
main = do
(arg1:_) <- getArgs
开发者_如何学C xs <- getContents
putStr (rotate xs arg1)
rotate input w1 = unlines [ process line | line <- lines input ]
where process line = unwords [ word | word <- words line ]
map rotate n xs = drop n xs ++ take n xs
Is any of this right so far and any clue/tips where to go next?
So a bit more like this:
shift :: a -> Int -> a
rotate :: a -> Int -> a
x shift i | i<0 = x shiftR (-i)
| i>0 = x shiftL i
| otherwise = x
x rotate i | i<0 = rotateR (-i)
| i>0 = rotateL i
| otherwise = x
The Quick answer:
Try this:
rotate :: Int -> [Char] -> [Char]
rotate x st = take (length st) $ drop (negate x `mod` length st) $ cycle st
It yields:
rotate (1) "hello"
>>> "ohell"
rotate (-1) "hello"
>>> "elloh"
The Explanation:
The insight needed for this to work, is knowledge of the cycle
function, which repeats a string forever.
cycle "ezra"
>>> "ezraezraezraezraezr..." (forever)
Using this knowledge, we can exploit length
, take
, and drop
to give us the part of the string that we want. We'll also use negate
and mod
for the math part.
length
length
returns the length of the list (strings are lists of characters).
length "ezra"
>>> 4
take
take n
returns the first n
items in a list.
take 9 (cycle "ezra")
>>> "ezraezrae"
drop
drop n
returns the whole list, except the first n
elements.
drop 3 "ezra"
>>> "a"
drop 3 (take 9 (cycle "ezra"))
>>> "aezrae"
mod
Using the mod
function, we can get the proper offsets. The backticks ` make the function "infix", which makes it more understandable. This is the "remainder" after the division, if you're not familiar with modular arithmetic.
10 `mod` 3
>>> 1
This will give us the starting point.
negate
negate n
returns the negation of n
, which we need to "reverse" the direction, and get the output you wanted.
negate 10
>>> -10
When we put it all together, we get the function above. There are, of course, many ways to do this: this is one.
In my solution above, I developed it in in the following order.
Get the infinite list:
rotate x st = cycle st
Take the right number of characters:
rotate x st = take (length st) $ cycle st
Take the characters from the right position:
rotate x st = take (length st) $ drop (x `mod` length st) $ cycle st
At this point I had what I wanted, but had to add negate
so that my output would match yours.
I also added the type signature. I like to have them explicit on as many of my functions as I can.
精彩评论