简体   繁体   中英

How to change a Char within a list of Strings in Haskell

I have just solved a question which involves changing a certain Char at a certain position with a String :

changeStr :: Int -> Char -> String -> String
changeStr x char zs = take (x-1) zs ++ [char] ++ drop x zs

-- This function takes an int input, a char and a string and then changes the string at the int position to the specified char. It does this by splitting the string into three parts, the first part is all the string before the specified postion, the second is the specified position and the third is all the string after the specified position. the second part is then changed to the specified character and everything is concatenated together.

{-

Cw2013> changeStr 2 'i' "dog"
"dig"

-}

Now I am basically trying to do something similar to the first question but doing it with a list of Strings by using the function changeStr as an auxilory function but I seem to be getting confused. I cant seem to solve it. Here is what I have done below :

changeRaw :: (Int,Int) -> Char ->  [String]-> [String]
changeRaw x y char zs = (take (y-1) zs) ++ (changeStr x char (head (take (y-1))) ++ (drop y zs)

Any suggestions on what I am doing wrong ?

The immediate fix for your problem is that your (head (take (y-1))) should instead be (head (drop (y-1) zs)) . A slightly better substitution would be to use (zs !! (y-1)) , since (!!) is the standard (zero-based) Haskell list indexing operation.

Also, note that the type signature (Int,Int) -> Char -> [String]-> [String] does not match your function pattern changeRaw xy char zs .


However, a more Haskellish solution would be simpler and more general:

-- generalized helper function
mapElt :: Int -> (a -> a) -> [a] -> [a]
mapElt n f xs = take (n-1) xs ++ f (xs!!(n-1)) : drop n xs

-- generic replacement for changeStr
setElt :: Int -> a -> [a] -> [a]
setElt n e xs = mapElt n (const e) xs

-- generic replacement for changeRaw
setElt2 :: Int -> Int -> a -> [[a]] -> [[a]]
setElt2 x y e xss = mapElt y (setElt x e) xss

Remaining annoyances include the one-based indexing, and the still-inelegant indexing mechanic in the mapElt implementation.

[updated to reflect edited question]

You have not general solution for changeStr .

You could do it more elegant:

changeNLst :: Int -> a -> [a] -> [a]

You have heavy solutions.

1) You could replace [char] ++ drop x zs with char : drop x zs

2) you could use splitAt :: Int -> [a] -> ([a], [a])

changeStr x char zs = before ++ (char : tail after)
    where (before, after) = splitAt (x-1) zs

The middle bit

changeStr x char (head (take (y-1))

is missing any mention of the list you want to take from.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM