This is not the most readable code ever; its goal is supreme elegance|2|, not instant clarity. It took me a couple of days thinking on-and-off, as well as a read-through of this almost equivalent Python transliteration|3| to finally understand what the hell is going on here.

The high level of what's going on here is that you're representing a board as a function of (Int, Int) -> [Int], and marking spaces by wrapping that function up in a dispatch/delete which returns pruned results in some circumstances.

This function uses some uncommon notation, and isn't really structured the way you'd expect in a Haskell program. That initial 12-line solution actually does a marginally better job of it. Here's a slightly revised, but equivalent version|7|

That uses the more common guard statements rather than a cascaded if/then/else. The input line and type signature on this one is what threw me for the longest time, so I'm going to linger there for a moment.

Remember, our Board is defined as ((Int, Int) -> [Int]), so that type signature could also be written

mark :: ((Int,Int),Int) -> (Int, Int) -> [Int] -> (Int, Int) -> [Int]

which should ironically clarify things. The actual arguments aren't doing anyone any favors either. The @s there are applying labels to some destructured constructs. The end result is that you can use the name p instead of (x, y) and p' instead of (x', y'). The following code is equivalent, but very slightly longer|8|:

This is the function that takes a board string and returns an actual board constructed from it. The main operation there is foldr, and I'm going to assume you understand how a fold works for this exercise. If you don't, read this and this, then do some googling. (const [1..9]) is a function that always returns the list of integers from 1 to 9, inclusive. It's equivalent to (&#95; -> [1,2,3,4,5,6,7,8,9])|9|. What it produces... is a bit trickier. It has to do with an inherent property of Haskell, and that type signature for mark I showed earlier.

mark :: ((Int,Int),Int) -> (Int, Int) -> [Int] -> (Int, Int) -> [Int]

First off, Haskell partially applies everything by default. Meaning that if you pass fewer than 4 arguments to mark, what you actually get back is a function that takes the next argument, and returns either the next partial or the final result. If you take a look at foldr, its type is

foldr :: (a -> b -> b) -> b -> [a] -> b

which means that it'll be treating mark as a function of two arguments. Note that the second argument is itself a function. Specifically, a (Int, Int) -> [Int], which means that mark will be getting three of its arguments filled. It might be easier to think about it like this

but since every function in Haskell can be applied partially, those are equivalent types. The end result of that fold operation is another function of (Int, Int) -> [Int]. Lets take a real close look at what's going on there.

Hopefully, now that I've unfoldrd the definition of input, this is intuitively obvious. search is an internal function that takes a list of boards and a space (x, y), and attempts to solve for them. It does this by taking each possibility for that space on each board and marking them, collecting all the results. If you look carefully, and have read those foldr links from earlier, this also explains why the Haskell version starts returning answers very quickly. The way iteration unfolds here, the first board is going to be solved quite a while before the complete sequence is solved, which means it'll be returned and printed quickly and thereafter not take further resources from the program.

The page "explaining" this code claims that it's "neither fast nor clever", and the Python version states that it's "Not the ideal way to solve Sudoku", but I'm honestly having a hard time imagining one that would give you any kind of gain, either in terms of performance or elegance|10|.

Possibly the most interesting thing about this solution for me is that, since it generates a list of all possible boards given a solution, you write a generator fairly simply|11| using something along the lines of choice $ solve [input . take 161 $ cycle "0 "], then redacting the results to a desired difficulty level. That might be another thing for me to throw some time at.

3 - |back| -Python doesn't have the same approach to partial functions that Haskell does, so the transliteration is both slightly easier to understand and slightly clunkier.|4| It also uses [foldl](http://foldl.com/) instead of [foldr](http://foldr.com/), because Python only comes with an implementation of foldl. Something tells me this kneecaps the .py versions' performance. Testing it out on the sample data listed at the bottom of this page, after manually sanitizing for spaces, seems to confirm that suspicion. On my machine, it spun up to 100% usage on one core until it occupied all of my memory, then sat there paging until I killed it. The Haskell solution, by contrast, starts producing results very close to instantly, puts all 4 cores to good use, and utterly fails to mem-rape my laptop before computing all possible solutions, which it does well before the Python version produces any solutions|5|.

4 - |back| -That's Python for you far as I can tell, in case you were wondering. It could almost be their slogan. "Python: Easier to understand and fatter than Haskell.".

5 - |back| -So I guess that slogan should really be "Python: Easier to understand, fatter and much slower than Haskell."|6|.

6 - |back| -Ok, that isn't entirely fair; this example wasn't optimized in any sense of the word. It uses list comprehensions instead of generators, and could probably implement a lazy foldr equivalent to start returning results right away. I'll put a bit of time into that later.

7 - |back| -As an aside here, it's mildly frustrating that every single gain in clarity in this exercise adds lines to the final count. I wish there was a way of being clearer while being more succinct.

8 - |back| -which I get the feeling is why the author chose to use the @s.

11 - |back| -I was going to say "Trivially", and then promptly lost 40 minutes to trying to figure out why exactly it is that an RVar [Int] can't be shown by default, or have its contents putStrd no matter how much liftM was applied. "Easier to understand, but fatter and slower than Haskell", also happens to be why I've been using Python at work. Haskell makes certain, very well understood things supremely easy, but as soon as I sit down to do something like output or randomness that's trivial in other languages, I find myself suffering a few hours of headaches before figuring it out. I also happen to agree with Sussman about the core point; implementing things that are very well understood is not the primary goal of programming.