# Getting the index (x,y) of a char in a "2D" list in Haskell

I have this working function circuitFind that I really don't find nice because I feel there is a better and simpler way to accomplish what it does.

circuitFind :: Circuit -> Tile -> Maybe Position
circuitFind c t = unpack . find (\ p -> fst p /= Nothing) . enumerate . map findTile $c where findTile = findIndex (==t) enumerate = flip zip [0..] unpack a = case a of Just (Just x, y) -> Just (x,y) _ -> Nothing  Basically, the function works like this: (ie: we search for the char '3') ["1stline", "2ndline", "3rdline"] | map findTile '3' | v [Nothing, Nothing, Just 0] | enumerate | v [(Nothing, 0), (Nothing, 1), (Just 0, 2)] | find (\ p -> fst p /= Nothing) | v Just (Just 0, 2) | unpack | v –– Just (0,2) ––  Is there a better way to make this function more readable/shorter/... ? All the relevant code here: import Data.List type Vec2D = (Int, Int) type Position = Vec2D type Circuit = [[Tile]] type Tile = Char basicCircuit :: Circuit basicCircuit = ["------------", "-b e-", "------------"] circuitFind :: Circuit -> Tile -> Maybe Position circuitFind c t = unpack . find (\ p -> fst p /= Nothing) . enumerate . map findTile$ c
where findTile = findIndex (==t)
enumerate = flip zip [0..]
unpack a = case a of
Just (Just x, y) -> Just (x,y)
_ -> Nothing


Some tests to illustrate the usage:

Main> circuitFind basicCircuit 'e'
Just (10,1)
Main> circuitFind basicCircuit 'o'
Nothing


Disclaimer: I'm rusty with Haskell, there may be a cleaner way to do this.

Code review: your code looks fine to my eyes, it's just that circuitFind is overly complex, as you suspected. Also note that findIndex (==t) can be written as elemIndex t (source).

"Let us see whether we could, by chance, conceive some other general problem that contains the original problem and is easier to solve." – Leibnitz.

We start by solving the more general problem of finding all indices of t in c.

Let's look at the skeleton of our solution.

[ (x,y) | ??? ]


We can get y using zip [0..] as you have done.

[ (x,y) | (y,line) <- zip [0..] c, ??? ]


Now we can find x using elemIndices.

[ (x,y) | (y,line) <- zip [0..] c, x <- elemIndices t line ]


Thanks to lazy evaluation, and Data.Maybe, we get our solution

circuitFind :: Circuit -> Tile -> Maybe Position
circuitFind c t = listToMaybe [ (x,y) | (y,line) <- zip [0..] c, x <- elemIndices t line ]

• I'll remember to use list comprehension the next time I have to do some filtering/processing, it really feels like the right tool for this purpose ! Commented Aug 4, 2014 at 18:28