开发者

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.

  1. Get the infinite list:

    rotate x st = cycle st
    
  2. Take the right number of characters:

    rotate x st = take (length st) $ cycle st
    
  3. 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.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜