好的,所以我知道这有点不对,但我错过了什么?代码是用以下单词旋转单个字母:
rotate 1 "hello" "ohell"
rotate -1 "hello" "elloh"
我的代码是:
module Main where
import System
main = do
(arg1:_) <- getArgs
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
到目前为止,这是否正确,任何线索/提示下一步去哪儿?
更像是这样:
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
答案 0 :(得分:20)
试试这个:
rotate :: Int -> [Char] -> [Char]
rotate x st = take (length st) $ drop (negate x `mod` length st) $ cycle st
它产生:
rotate (1) "hello"
>>> "ohell"
rotate (-1) "hello"
>>> "elloh"
这需要的洞察力是cycle
函数的知识,它永远重复一个字符串。
cycle "ezra"
>>> "ezraezraezraezraezr..." (forever)
利用这些知识,我们可以利用length
,take
和drop
为我们提供我们想要的字符串部分。我们还会将negate
和mod
用于数学部分。
length
返回列表的长度(字符串是字符列表)。
length "ezra"
>>> 4
take n
返回列表中的第一个n
项。
take 9 (cycle "ezra")
>>> "ezraezrae"
drop n
返回整个列表,但第一个n
元素除外。
drop 3 "ezra"
>>> "a"
drop 3 (take 9 (cycle "ezra"))
>>> "aezrae"
使用mod
功能,我们可以获得正确的偏移量。反引号`使函数“中缀”,这使它更容易理解。如果您不熟悉modular arithmetic,那么这就是除法后的“余数”。
10 `mod` 3
>>> 1
这将为我们提供起点。
negate n
返回n
的否定,我们需要“反转”方向,并获得您想要的输出。
negate 10
>>> -10
当我们把它们放在一起时,我们得到了上面的功能。当然,有很多方法可以做到这一点:这是一个。
在上面的解决方案中,我按以下顺序开发了它。
获取无限列表:
rotate x st = cycle st
选择正确数量的字符:
rotate x st = take (length st) $ cycle st
从正确的位置取字符:
rotate x st = take (length st) $ drop (x `mod` length st) $ cycle st
此时我有我想要的东西,但必须添加negate
以便我的输出与你的相匹配。
我还添加了类型签名。我希望尽可能多地明确我的功能。