Ralph
Ralph

Reputation: 32264

Haskell mutable array for sudoku grid

I'm trying to write a sudoku generator/solver in Haskell as a learning exercise, but I'm running into difficulty producing a mutable array in the ST monad.

The input to my parse function will be a String of 81 characters containing the digits 1 through 9 and placeholders (., -, or 0).

This is the function that I wrote, but it will not compile and I can't figure out what types I need:

import           Control.Monad
import           Control.Monad.ST
import           Data.Array.ST
import qualified Data.Array.Unboxed as U
import           Data.Char          (digitToInt, isDigit)
import           Data.List          (zip)

data Cell = Cell
  { values   :: Word16
  , original :: Bool
  } deriving (Show)

parse input =
  runSTUArray $
  U.array ((0, 0), (8, 8)) $
  map
    (\(i, d) ->
       ( (quot i 9, mod i 9)
       , if isDigit d && d /= '0'
           then Cell {values = bit $ digitToInt d, original = True}
           else Cell {values = 2 ^ 11 - 2, original = False})) $
  zip [0 ..] input

The output of the function should be an immutable representation of a mutable 9 x 9 grid containing cells.

How can I fix this?

Upvotes: 0

Views: 139

Answers (1)

HTNW
HTNW

Reputation: 29148

You are using runSTUArray, which implies the intent to have a UArray (Int, Int) Cell. You can't have this: UArray is meant only for a select few element types. You can use a normal Array. Or, you can have type Cell = Word16 and just cram the Bool into it. In any case, there is no reason to use ST. The listArray function will do:

import Data.Array
-- listArray :: Ix i => (i, i) -> [e] -> Array i e

parse :: String -> Array (Int, Int) Cell
parse = listArray ((0, 0), (8, 8)) . map chr2cell
  where chr2cell c | isDigit c && c /= '0' = Cell (bit $ intToDigit c) True
                   | otherwise = Cell (2^11 - 2) False

If you choose to use UArray _ Word16, you simply need to modify chr2cell a bit. If you are on recent GHC, you can even opt to have:

{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
type Cell = Word16
pattern Cell :: Word16 -> Bool -> Word16
pattern Cell { values, original } <- (_ -> (values, original))
  where Cell values original = _

where you can fill the first and second _s with functions that deconstruct and construct cells to/from a Word16 and a Bool, respectively, to create a record pattern synonym that works just like a normal record constructor but doesn't actually create a new type.

Upvotes: 1

Related Questions