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 -&gt; Tile -&gt; Maybe Position
circuitFind c t = unpack . find (\ p -&gt; fst p /= Nothing) . enumerate . map findTile $ c
    where findTile = findIndex (==t)
          enumerate = flip zip [0..]
          unpack a = case a of 
             Just (Just x, y) -&gt; Just (x,y) 
             _ -&gt; 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 -&gt; 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 -&gt; Tile -&gt; Maybe Position
circuitFind c t = unpack . find (\ p -&gt; fst p /= Nothing) . enumerate . map findTile $ c
    where findTile = findIndex (==t)
          enumerate = flip zip [0..]
          unpack a = case a of 
             Just (Just x, y) -&gt; Just (x,y) 
             _ -&gt; Nothing


Some tests to illustrate the usage:

Main&gt; circuitFind basicCircuit 'e'
Just (10,1)
Main&gt; 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) &lt;- zip [0..] c, ??? ]


Now we can find x using elemIndices.

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


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

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