Gikicio
Gikicio

Reputation: 31

Swapping 2 characters in list of strings (Haskell)

I need to swap blank space with letter from "moves" and each time I swap it I need to continue with another one from moves. I get Couldn't match expected type, even though I just want to return value x when it doesn't meet condition.

Error message:

[1 of 1] Compiling Main             ( puzzlesh.hs, interpreted )

puzzlesh.hs:19:43: error:
• Couldn't match expected type ‘Int -> a’ with actual type ‘Char’
• In the expression: x
  In the expression: if x == ' ' then repl x else x
  In an equation for ‘eval’: eval x = if x == ' ' then repl x else x
• Relevant bindings include
    eval :: Char -> Int -> a (bound at puzzlesh.hs:19:5)
    repl :: forall p. p -> Int -> a (bound at puzzlesh.hs:20:5)
    moves :: [a] (bound at puzzlesh.hs:16:9)
    p :: t [Char] -> [a] -> [Int -> a] (bound at puzzlesh.hs:16:1)
   |
19 |     eval x = if x == ' ' then repl x else x
   |                                           ^
Failed, no modules loaded.

Code:

import Data.Char ( intToDigit )
sample :: [String]
sample = ["AC DE",
"FBHIJ",
"KGLNO",
"PQMRS",
"UVWXT"]

moves = "CBGLMRST"

type Result = [String]

pp :: Result -> IO ()
pp x = putStr (concat (map (++"\n") x))

p input moves = [eval x | x <- (concat input)]
  where
    c = 1
    eval x = if x == ' ' then repl x else x
    repl x count = moves !! count
    count c = c + 1

I need to take character from moves, replace it onto blank space and do this till moves is []

Desired output:

ABCDE
FGHIJ
KLMNO
PQRST
UVWX

Upvotes: 0

Views: 167

Answers (1)

Chris
Chris

Reputation: 36496

As with most problems, the key is to break it down into smaller problems. Your string that encodes character swaps: can we break that into pairs?

Yes, we just need to create a tuple from the first two elements in the list, and then add that to the result of calling pairs on the tail of the list.

pairs :: [a] -> [(a, a)]
pairs (x:tl@(y:_)) = (x, y) : pairs tl 
pairs _ = []

If we try this with a string.

Prelude> pairs "CBGLMRST"
[('C','B'),('B','G'),('G','L'),('L','M'),('M','R'),('R','S'),('S','T')]

But you want a blank space swapped with the first character:

Prelude> pairs $ " " ++ "CBGLMRST"
[(' ','C'),('C','B'),('B','G'),('G','L'),('L','M'),('M','R'),('R','S'),('S','T')]

Now you have a lookup table with original characters and their replacements and the rest is straightforward. Just map a lookup on this table over each character in each string in the list.

Because you never touch any letter in the original strings more than once, you won't have to worry about double replacements.

Prelude> s = ["AC DE","FBHIJ","KGLNO","PQMRS","UVWXT"]
Prelude> r = "CBGLMRST"
Prelude> r' = " " ++ r
Prelude> p = pairs r'
Prelude> [[case lookup c p of {Just r -> r; _ -> c} | c <- s'] | s' <- s]
["ABCDE","FGHIJ","KLMNO","PQRST","UVWXT"]

Upvotes: 1

Related Questions