user2998031
user2998031

Reputation: 1

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 ?

Upvotes: 0

Views: 1343

Answers (3)

wit
wit

Reputation: 1622

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

Upvotes: 1

comingstorm
comingstorm

Reputation: 26097

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 x y 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]

Upvotes: 1

Robin Green
Robin Green

Reputation: 33033

The middle bit

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

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

Upvotes: 0

Related Questions