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
asked Aug 3, 2014 at 20:46
\$\endgroup\$

1 Answer 1

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 ]
answered Aug 4, 2014 at 0:51
\$\endgroup\$
1
  • \$\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\$ Commented Aug 4, 2014 at 18:28

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.