Context
The original idea is to create an efficient grid structure for a Sudoku like board but this can be applied to many such grid structures (like wavelet transform on images, JPEG2000 etc). This particular one is basically a 9x9 Board
which is made up of 3x3 Block
s where each Block
is made up of 3 x Axis a a a
type. You may think Axis
type like a list limited to having only 3 elements (no more no less) and no empty or identiy element.
I have defined the Axis
, Block
and Board
types as;
data Axis a = Axis { _0 :: a
, _1 :: a
, _2 :: a
} deriving (Eq, Functor)
type Block a = (Axis(Axis a))
type Board a = (Axis(Axis (Block a)))
instance Show a => Show (Axis a) where
showsPrec _ (Axis x y z) = shows x . (' ':) . shows y . (' ':) . shows z
As you notice, polymorphic Axis
type is like a ternary tree with no leaves where the nodes can either be another Axis a
type or an a
type value. Does anybody know a general name for such data types in Haskell literature?
Anyways, by doing so, once i have a Board
then i can easily access any Block
or Cell
quite efficiently. To access one of the 9 Block
s i can now simply do
_0 . _1 $ myBoard -- like (row 0, col 1) from myBoard
where to gain access to any cell within the Board
all i have to do is to get to the Block
and then to the cell like
_2 . _1 . _0 . _1 $ myBoard -- coord of cell . coord of Block => (_2 . _1) . (_0 . _1)
Problem
The problem arose when building up my Board
type from a provided String
. Since i post this here, I have done it but it smells like a fish and i think there must be a better way.
So the input data comes in the form of a string of 81 numeric characters among 0..9
. The string should fill up the board line by line. So if my board supposed to be a 2D list, then a chunksOf 9 . map ((read :: String-> Int) . pure)
would be sufficient. However the Board
type is a 4 fold nested Axis
type.
To start with, I couldn't even find a way to write a Read
instance for the Board
type at all. My solution is to first convert the flat list into a nested list of proper structure like.
nestList :: [a] -> [[[[a]]]]
nestList = map transpose . chunksOf 3 . chunksOf 3 . chunksOf 3
and then after a 2 days war with GHC infinite type errors and whatnot, i could finally come up with this stinky part.
axify :: [[[[a]]]] -> Board a
axify ([a,b,c]) = Axis (Axis (axify' $ a !! 0) (axify' $ a !! 1) (axify' $ a !! 2))
(Axis (axify' $ b !! 0) (axify' $ b !! 1) (axify' $ b !! 2))
(Axis (axify' $ c !! 0) (axify' $ c !! 1) (axify' $ c !! 2))
where
axify' ([a,b,c]) = Axis (Axis (a !! 0) (a !! 1) (a !! 2))
(Axis (b !! 0) (b !! 1) (b !! 2))
(Axis (c !! 0) (c !! 1) (c !! 2))
Now this works. I can fill the Board
properly from a flat string and the Show
instance just gives back a stringified version of the nestedList
.
Question
Could anybody please help me with a proper Read
instance or at least an axify
function that is idiomatic (generalized to n
fold Axis a
type)?
Many thanks in advance.