5
\$\begingroup\$

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
| improve this question | | | | |
\$\endgroup\$
3
\$\begingroup\$

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 ]
| improve this answer | | | | |
\$\endgroup\$
  • \$\begingroup\$ 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 ! \$\endgroup\$ – Cranium Aug 4 '14 at 18:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.