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
1 Answer 1
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 ]
-
\$\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– Cranium2014年08月04日 18:28:38 +00:00Commented Aug 4, 2014 at 18:28