#1 |
![slide 1](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-1.png) |
|
#2 |
![slide 2](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-2.png) |
|
#3 |
![slide 3](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-3.png) |
- What we are trying to do in the 8-Queens puzzle is find ways of placing 8 queens on an 8 by 8 chessboard so that no two queens are on the same row, the same column and the same diagonal (no two queens hold each other in check – no two queens attack each other).
|
#4 |
![slide 4](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-4.png) |
- How many ways are there of placing the queens on the board?
|
#5 |
![slide 5](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-5.png) |
- For the first queen, I have a choice of 8 x 8 = 64 cells where I can place it.
- For the next queen, I have one less choice, i.e. 63.
- And so on, until I get to the 8th queen, at which point I have only one choice left.
|
#6 |
![slide 6](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-6.png) |
- And if we multiply those numbers, we find that there are more than 178 trillion ways of placing the queens.
|
#7 |
![slide 7](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-7.png) |
- But we can arrive at the same queen configuration in different ways.
- If we consider a particular placement of the queens e.g. this one, how many way are there of arriving at it ?
|
#8 |
![slide 8](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-8.png) |
- When we pick the first queen, we have 8 choices.
- When we pick the second queen, we have one less choice, i.e. 7.
- And so on, until we pick the eighth queen, at which point we have only one choice left.
|
#9 |
![slide 9](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-9.png) |
- And if we multiply those numbers, we find that there are more than (8!) 40,000 ways of arriving at the same queen configuration.
|
#10 |
![slide 10](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-10.png) |
- So, if we want to work out the number of ways of placing the queens so that we arrive at a unique queen configuration, we divide the first number by the second number
|
#11 |
![slide 11](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-11.png) |
- And if we do the math, we see that there are still more than 16 billion ways of arriving at a unique configuration.
|
#12 |
![slide 12](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-12.png) |
- If we take into account that no two queens can be on the same row, then we can drastically reduce the number of candidate boards that we need to consider when looking for a solution.
|
#13 |
![slide 13](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-13.png) |
- To do that, we start from the top row, and move downwards, placing one queen on each row. On each row, there are 8 ways of placing a queen.
- And if we do the maths, we find that there are 88 ways of doing that, i.e. still more than 16 million ways of doing that.
|
#14 |
![slide 14](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-14.png) |
- We also know that no two queens can be on the same column. So we can again reduce the number of candidate boards we need to consider.
|
#15 |
![slide 15](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-15.png) |
- To do that, we make sure that when placing a queen, we choose a column that has not already been picked.
- And if we do the math we see that there are (again that number 8!) more than 40,000 ways of doing that.
- And while we have not yet taken into account that no two queens can be on the same diagonal either, this does give us a good idea of where we are headed in terms of the candidate boards that need to be considered when looking for a solution (we have already greatly reduced the number of candidate boards by several orders of magnitude).
|
#16 |
![slide 16](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-16.png) |
- Let’s try to find a solution to the puzzle.
|
#17 |
![slide 17](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-17.png) |
|
#18 |
![slide 18](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-18.png) |
- We place the first queen and cross out the rows, columns and diagonals which are no longer available for placing upcoming queens (because they would be held in check by the queen).
|
#19 |
![slide 19](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-19.png) |
- We place the second queen, and again cross out.
|
#20 |
![slide 20](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-20.png) |
- We place the third queen, and again cross out.
|
#21 |
![slide 21](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-21.png) |
- We place the fourth queen, and again cross out.
|
#22 |
![slide 22](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-22.png) |
- We place the fifth queen, and again cross out.
|
#23 |
![slide 23](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-23.png) |
- But when we try to place the sixth queen, we are stuck.
- There is nowhere to place it because all the empty cells on the board are held in check by the previously placed queens.
|
#24 |
![slide 24](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-24.png) |
|
#25 |
![slide 25](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-25.png) |
|
#26 |
![slide 26](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-26.png) |
- We place the first queen, and cross out.
|
#27 |
![slide 27](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-27.png) |
- We place the second queen, and cross out.
|
#28 |
![slide 28](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-28.png) |
- We place the third queen, and again cross out.
- With a bit of luck, we'll find a solution.
|
#29 |
![slide 29](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-29.png) |
|
#30 |
![slide 30](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-30.png) |
|
#31 |
![slide 31](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-31.png) |
|
#32 |
![slide 32](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-32.png) |
|
#33 |
![slide 33](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-33.png) |
|
#34 |
![slide 34](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-34.png) |
|
#35 |
![slide 35](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-35.png) |
- The 8-Queens puzzle has always featured in the official Scala book and Scala FP course co-authored by Martin Odersky, because such combinatorial puzzles are particularly suited to solving with for expressions.
|
#36 |
![slide 36](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-36.png) |
- The 8-Queens puzzle is a special case of the more general N-Queens puzzle, in which we have to place N-Queens on an N by N chessboard. Solutions exist for all positive integers N with the exception of 2 and 3.
|
#37 |
![slide 37](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-37.png) |
- In the Scala book, a candidate solution is represented as a list of pairs, with each pair consisting of the row number and column number where a queen is located. The rows and columns start at 1.
|
#38 |
![slide 38](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-38.png) |
- In the Scala FP course, the rows and columns start at 0. Because it is obvious that the Nth queen is in the Nth row, there is no need to be explicit about it, and so a solution is represented by a list of column numbers.
|
#39 |
![slide 39](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-39.png) |
- In the Scala FP course, Odersky provides a ‘show’ function to display a candidate solution board on the console.
|
#40 |
![slide 40](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-40.png) |
- Here is the code for the ‘show’ function. I have tweaked it slightly to use a cross for an empty cell and a crown for a populated cell.
|
#41 |
![slide 41](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-41.png) |
- If we take the representation of a candidate solution board, e.g. this one…
|
#42 |
![slide 42](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-42.png) |
- …and we pass it to the show function, and print the result…
|
#43 |
![slide 43](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-43.png) |
- …we get this, which is pretty good.
|
#44 |
![slide 44](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-44.png) |
- But now let’s look at how we can use a graphics library like Doodle to create an image of a candidate solution board.
|
#45 |
![slide 45](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-45.png) |
- We can easily use Doodle to create a 100 pixel by 100 pixel red square image...
|
#46 |
![slide 46](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-46.png) |
|
#47 |
![slide 47](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-47.png) |
- In Doodle there is a beside function, which takes two images and returns a composite image that is the first image beside the second image.
|
#48 |
![slide 48](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-48.png) |
- Similarly, there is an above function, which takes two images and returns a composite image that is the first image above the second image.
|
#49 |
![slide 49](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-49.png) |
- So, if we have a candidate solution board…
|
#50 |
![slide 50](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-50.png) |
- …what we can do is create square images for each of the cells in the board, a white square for an empty cell, and a red square for a populated cell.
|
#51 |
![slide 51](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-51.png) |
- And then we can use the beside and above functions to stitch the square images into a single composite image for the whole board.
|
#52 |
![slide 52](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-52.png) |
- So, let’s create ourselves a white square image and a red square image…
|
#53 |
![slide 53](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-53.png) |
- And now we can write ourselves a combine function which takes a grid of square images and returns an image that is the composition of all those images.
|
#54 |
![slide 54](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-54.png) |
- The way it works is that it first maps over the rows of square images.
|
#55 |
![slide 55](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-55.png) |
- For each row of images, it reduces the images with the beside function, stitching them together, one beside the other, into a single composite image for the whole row.
|
#56 |
![slide 56](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-56.png) |
- Once it has done that, it takes the resulting images for the rows, and combines them with the above function, stitching them together, one above the other, into a single composite image for the whole board.
|
#57 |
![slide 57](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-57.png) |
- Our combine function is using the reduce function, which is unsafe in that when reduce is invoked on an empty collection it throws an exception.
|
#58 |
![slide 58](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-58.png) |
- To be on the safe side, let’s use the fold function instead of the reduce function. To do that, we must tell the fold function what to return when the collection is empty, so we tell it to return the empty image.
|
#59 |
![slide 59](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-59.png) |
- Also, fold is just an alias for foldLeft, so let’s make that explicit.
|
#60 |
![slide 60](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-60.png) |
- In this section of the talk, we need the notion of a monoid. For the purposes of this talk, a monoid consists of three things. The first thing is the set of elements of a given type, e.g., the positive integer numbers. The second thing is a binary associative operation on the elements of that type, e.g., integer addition. And the third thing is an identity element for the binary operation, e.g., zero. In the foldable trait, in the red book, we see a ‘concatenate’ function that operates on a foldable of A, and takes as argument a monoid for A. The ‘concatenate’ function does a left fold of the As, using the monoid’s identity as the initial accumulator, and using the monoid’s binary operation to combine all the foldable’s As into an A.
|
#61 |
![slide 61](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-61.png) |
- In Cats, the ‘concatenate’ function is called ‘fold’, but there is also a ‘combineAll’ alias, to avoid clashes with the ‘fold’ function in the Scala standard library.
|
#62 |
![slide 62](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-62.png) |
- Let’s skip the following slides, which are an introduction to (or a refresher on) monoids.
|
#63 |
![slide 63](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-63.png) |
|
#64 |
![slide 64](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-64.png) |
|
#65 |
![slide 65](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-65.png) |
|
#66 |
![slide 66](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-66.png) |
|
#67 |
![slide 67](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-67.png) |
|
#68 |
![slide 68](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-68.png) |
|
#69 |
![slide 69](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-69.png) |
|
#70 |
![slide 70](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-70.png) |
|
#71 |
![slide 71](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-71.png) |
|
#72 |
![slide 72](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-72.png) |
|
#73 |
![slide 73](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-73.png) |
|
#74 |
![slide 74](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-74.png) |
|
#75 |
![slide 75](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-75.png) |
- Back to the code for our ‘combine’ function. It does a ‘foldLeft‘, with the empty image as initial accumulator and the ‘beside’ function as binary operation.
|
#76 |
![slide 76](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-76.png) |
- What we can do is use Cats to define a monoid for images, whose identity is the empty image, and whose binary operation is the ‘beside’ function. For lack of imagination, let’s call this the ‘beside’ monoid.
|
#77 |
![slide 77](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-77.png) |
- And now, instead of doing a left fold with the empty image and the ‘beside’ function, we can do a ‘combineAll’ with the ‘beside’ monoid.
|
#78 |
![slide 78](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-78.png) |
- In the ‘foldable’ trait, we also see another function, called ‘foldMap’, which builds on top of the functionality provided by ‘concatenate’. It also operates on a ‘foldable’ of As, but it takes an additional parameter f, which is a function from A to B. Also, not that the monoid parameter is for B rather than for A. Logically, what ‘foldMap’ does is first map the As to Bs, and then proceed the same way that ‘concatenate’ does, i.e., by folding the elements using the monoid’s identity and binary operation. By the way, on this slide, ‘foldMap’ is implemented using ‘foldRight’, but it can just as well be implemented using ‘foldLeft’ (see next slide).
|
#79 |
![slide 79](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-79.png) |
|
#80 |
![slide 80](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-80.png) |
- Back to the code for our ‘combine’ function.
|
#81 |
![slide 81](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-81.png) |
- Purely to make the next step easier to understand, let’s revert to using the unsafe ‘reduce’ function rather than ‘foldLeft’.
|
#82 |
![slide 82](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-82.png) |
|
#83 |
![slide 83](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-83.png) |
- Our ‘combine’ function is doing a map of a function, followed by a reduce with the ‘above’ function.
- A map followed by a reduce is exactly what ‘foldMap’ does (the function we have just seen).
|
#84 |
![slide 84](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-84.png) |
- What we can do is use Cats to define another monoid for images.
- Its identity is still the empty image, but its binary operation is the ‘above’ function.
- Again, for lack of imagination, let’s call it the ‘above’ monoid.
|
#85 |
![slide 85](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-85.png) |
- Now, instead of doing a map with a function, followed by a reduce with the ‘above’ function, we can do a ‘foldMap’ with the function and with the ‘above’ monoid.
|
#86 |
![slide 86](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-86.png) |
- Here is a recap of the start and end points of our small refactoring journey.
|
#87 |
![slide 87](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-87.png) |
- And it works, the refactored code produces exactly the same result (on this slide, I am using the ‘fold’ name rather than the ‘combineAll’ one).
|
#88 |
![slide 88](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-88.png) |
- Now let’s go back to the show function…
|
#89 |
![slide 89](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-89.png) |
- …and where it uses crosses and crowns, let’s use white square images, and red square images…
|
#90 |
![slide 90](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-90.png) |
- …and where it stitches together smaller strings into larger strings, let’s put the square images into a grid, and pass them to our ‘combine’ function, so that instead of getting a string representation of a candidate solution board, we get a composite image for the board.
|
#91 |
![slide 91](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-91.png) |
|
#92 |
![slide 92](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-92.png) |
- We can do a bit more though.
|
#93 |
![slide 93](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-93.png) |
- The images that we have been creating up to now have been centred on the origin of the coordinate system.
|
#94 |
![slide 94](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-94.png) |
- In Doodle, if call an image’s ‘at’ function with the coordinates of a desired location, we get back the same image but centred on that location. And if we are prepared to do that, then we can further simplify how we combine images.
|
#95 |
![slide 95](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-95.png) |
- Back to our combine function.
|
#96 |
![slide 96](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-96.png) |
- We can now use Cats to define another image monoid, one whose identity is still the empty image, but whose binary operation is the ‘on’ function, which takes two images, and returns a composite image that is the first image superimposed on the second image.
- Again, for lack of imagination, let’s call this the ‘on’ monoid.
|
#97 |
![slide 97](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-97.png) |
- Now instead of using the ‘beside’ and ‘above’ monoids, we can just use the ‘on’ monoid.
|
#98 |
![slide 98](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-98.png) |
|
#99 |
![slide 99](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-99.png) |
- And if we make the ‘on’ monoid implicit, i.e., if we say that the default monoid for images is the ‘on’ monoid, then we can simplify things further, because ‘foldMap’ and ‘combineAll’ are happy to take the ‘on’ monoid implicitly.
|
#100 |
![slide 100](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-100.png) |
- To recap, here are the start and end points of our whole refactoring journey, and hopefully you’ll agree that the bottom function is simpler, provided we understand what ‘foldMap’ and ‘combineAll’ do, and what the ‘on’ monoid is.
|
#101 |
![slide 101](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-101.png) |
|
#102 |
![slide 102](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-102.png) |
- Earlier we looked at the number of ways of placing 8 queens on an 8 by 8 chessboard, one queen per row. We came across 88, which is the number of permutations of 8 queens, allowing repetition, and 8!, which is the number of permutations of 8 queens disallowing repetitions.
|
#103 |
![slide 103](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-103.png) |
- So, for arbitrary N, the formulas are N to the power of N and N!
|
#104 |
![slide 104](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-104.png) |
- But how do we compute the permutations of N queens, e.g. for N=4?
|
#105 |
![slide 105](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-105.png) |
- We can use this simple program.
- The for expression first chooses a column number, between 1 and 4, for the first queen.
- Then it does the same for the 2nd, 3rd and 4th queen. It then puts the results in a List, which it then yields.
|
#106 |
![slide 106](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-106.png) |
- And if we run the code, we find that it does indeed generate the list of permutations of column numbers 1 through to 4, allowing repetitions (you can see repeating column numbers in some permutations).
|
#107 |
![slide 107](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-107.png) |
- And if we were to print some stats, we’d see that the number of permutations is indeed 4 to the power of 4, i.e. 256 (as opposed to N! = 24).
|
#108 |
![slide 108](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-108.png) |
- And if we create the appropriate square images and pass them to our combine function, then here are the images that it produces for the 256 permutations.
|
#109 |
![slide 109](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-109.png) |
- But how many of these are solutions?
|
#110 |
![slide 110](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-110.png) |
- That depends on N. For N=4, there are 2 solutions.
|
#111 |
![slide 111](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-111.png) |
- Here they are, highlighted in green.
|
#112 |
![slide 112](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-112.png) |
- But how do we find the solutions?
|
#113 |
![slide 113](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-113.png) |
- Martin Odersky suggests using recursion, so let’s refactor our permutations function to use recursion.
|
#114 |
![slide 114](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-114.png) |
|
#115 |
![slide 115](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-115.png) |
|
#116 |
![slide 116](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-116.png) |
- Here is the function again.
|
#117 |
![slide 117](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-117.png) |
- We are going to simplify it so that it does divide and conquer, using recursion.
|
#118 |
![slide 118](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-118.png) |
- To compute the permutations of N queens, we first recursively compute the permutations of N-1 queens.
|
#119 |
![slide 119](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-119.png) |
- This recursive call results in further recursive calls, eventually reaching the base case call, which computes the permutations of zero queens, and which results in a single permutation that is empty.
|
#120 |
![slide 120](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-120.png) |
- When we come out of a recursive call, we have a partial permutation, which we name ‘queens’.
- We then pick a new column number that we name ‘queen’.
|
#121 |
![slide 121](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-121.png) |
- We then cons ‘queen’ onto ‘queens’, to create a more complete permutation.
|
#122 |
![slide 122](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-122.png) |
- Our refactoring works: if we run the resulting, code we get exactly the same result.
|
#123 |
![slide 123](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-123.png) |
- Here is the recursive code for the N-Queens puzzle, both from the book, and from the course.
- You can see that the two programs are pretty much the same, except that they both use an ‘isSafe’ function that we have not discussed yet.
|
#124 |
![slide 124](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-124.png) |
- On the left we have the permutation function that we have just refactored to use recursion, and on the right, we have the heart of the recursive code for the N-Queens puzzle.
- You can see that the code on the left is hard-coded to work only for N=4, whereas the code on the right is more general in that it works for an arbitrary N.
- You can also see that the code on the right uses the ‘isSafe’ function that we have not discusses so far.
|
#125 |
![slide 125](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-125.png) |
- For the purposes of this talk, the only thing that we are going to say about the ‘isSafe’ function is what it does: If you give it a partial queens permutation computed so far, and a proposed location (column number) for the next queen, it returns, yes or no, true or false, whether or not it is safe to place the next queen in that location.
- The way it does it is by checking whether the next queen is in the same row, column or diagonal as any of the queens in the partial permutation.
|
#126 |
![slide 126](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-126.png) |
- Let’s refactor our permutations function to use the ‘isSafe’ function.
- Once we have chosen a column for the next queen, we call the ‘isSafe’ function to find out if it is safe to place the queen in that column, and only if it is safe, do we proceed in the for comprehension, otherwise we backtrack.
|
#127 |
![slide 127](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-127.png) |
|
#128 |
![slide 128](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-128.png) |
- And if we run the refactored code we find that the vast majority of the permutations are considered unsafe and are thus filtered out and discarded, which leaves us with just two permutations…
|
#129 |
![slide 129](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-129.png) |
- …the two solution that we saw earlier.
|
#130 |
![slide 130](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-130.png) |
- Let’s visualise how the filtering process reduces the problem space.
|
#131 |
![slide 131](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-131.png) |
- We start off with an empty 4 by 4 board.
|
#132 |
![slide 132](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-132.png) |
- We then place the first queen on the board. There are four ways of doing that.
|
#133 |
![slide 133](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-133.png) |
- For each of the four resulting boards, we then place the second queen, and again there are four ways of doing that.
- The ‘isSafe’ function kicks in and identifies some boards as being unsafe, so I have marked them in yellow.
|
#134 |
![slide 134](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-134.png) |
- For each of the remaining safe boards, the white ones, we then place the third queen. Again, there are four ways of doing that.
- I have again marked in yellow the new boards that the ‘isSafe’ function considers unsafe.
- I have also marked in orange some placeholders for boards that are not even generated, let alone checked for safety, because they originate from previous boards deemed unsafe.
|
#135 |
![slide 135](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-135.png) |
- On the remaining safe boards (the white ones), we now place the fourth queen.
- Again, there are four ways of doing that, and again, new unsafe boards are marked in yellow, and new placeholders, for boards not generated, are in orange.
- We see that almost all generated boards are yellow, i.e. unsafe, and the remaining two, the solutions, are in green.
- So, the recursive algorithm generated 60 out of 256 possible boards, and found 2 solutions.
|
#136 |
![slide 136](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-136.png) |
- Here are the two solutions again, the ones for N=4.
|
#137 |
![slide 137](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-137.png) |
- When N=5 there are 10 solutions.
|
#138 |
![slide 138](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-138.png) |
- When N=6 there are 4 solutions.
|
#139 |
![slide 139](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-139.png) |
- When N=7 there are 40 solutions.
|
#140 |
![slide 140](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-140.png) |
- When N=8 there are 92 solutions.
|
#141 |
![slide 141](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-141.png) |
- You can see that the number of solutions varies quite a bit depending on the value of N.
|
#142 |
![slide 142](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-142.png) |
- Here is the code for the recursive solution to the N-Queens puzzle, both in Scala and in Haskell, with some unimportant tweaking of the ‘isSafe’ function and its helper functions.
|
#143 |
![slide 143](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-143.png) |
- I went to the Rosetta Code web site, looking for alternative Haskell solutions to the puzzle.
- I found one which did not use recursion. It used a function called ‘foldM’, which I had not came across before.
- The variable names that it used did not seem helpful to me.
- It was succinct.
- Also, it was heavily commented, suggesting that it was not easy to understand, at least by people new to the ‘foldM’ function.
|
#144 |
![slide 144](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-144.png) |
- In the rest of this talk we will gain an understanding of the ‘foldM’ function, and see how it can be used to write an iterative solution to the puzzle.
|
#145 |
![slide 145](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-145.png) |
- We are all very familiar with the three functions that are the bread, butter and jam of functional programming…
|
#146 |
![slide 146](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-146.png) |
- …i.e. the triad of map, filter and fold.
|
#147 |
![slide 147](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-147.png) |
- Let’s gain an understanding of the ‘foldM’ function by looking at the monadic variant of the triad, i.e. ‘mapM’, ‘filterM’ and ‘foldM’.
|
#148 |
![slide 148](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-148.png) |
|
#149 |
![slide 149](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-149.png) |
- I came across the function in this Haskell book.
|
#150 |
![slide 150](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-150.png) |
- We are all very familiar with the map function.
- It takes a function from A to B, and a list of As, and maps it to a list of Bs.
|
#151 |
![slide 151](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-151.png) |
- What we want to do is understand how ‘mapM’ works.
- We are going to look at the Scala code for it, which we can write ourselves using the Cats Monad type class.
|
#152 |
![slide 152](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-152.png) |
|
#153 |
![slide 153](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-153.png) |
- But before we do that, where does ‘mapM’ live in Haskell and in Scala?
|
#154 |
![slide 154](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-154.png) |
- As Runar Bjarnason (co-author of the red book) says, in Scala, if the question is “how do I do this?”, then the answer is either “don’t do it”, or “traverse” (and its companion function, ‘sequence’).
|
#155 |
![slide 155](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-155.png) |
- Let’s skip the following introduction (or refresher) to the ‘traverse’ function.
|
#156 |
![slide 156](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-156.png) |
|
#157 |
![slide 157](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-157.png) |
|
#158 |
![slide 158](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-158.png) |
|
#159 |
![slide 159](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-159.png) |
|
#160 |
![slide 160](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-160.png) |
|
#161 |
![slide 161](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-161.png) |
|
#162 |
![slide 162](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-162.png) |
|
#163 |
![slide 163](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-163.png) |
|
#164 |
![slide 164](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-164.png) |
|
#165 |
![slide 165](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-165.png) |
|
#166 |
![slide 166](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-166.png) |
|
#167 |
![slide 167](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-167.png) |
|
#168 |
![slide 168](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-168.png) |
- In Haskell, the ‘traverse’ function lives in the ‘traversable’ type class.
|
#169 |
![slide 169](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-169.png) |
- Let’s compare the signatures of the ‘map’ and ‘mapM’ functions.
|
#170 |
![slide 170](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-170.png) |
- While ‘map’ takes a function that returns a B, ‘mapM’ takes a function that also returns a B, but in a monadic context.
|
#171 |
![slide 171](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-171.png) |
- And while ‘map’ returns a list of Bs, ‘mapM’ also returns a list of Bs, but in a monadic context.
|
#172 |
![slide 172](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-172.png) |
- It turns out that in Haskell, ‘mapM’ is defined as ‘traverse’.
- While ‘traverse’ is based on the Applicative type class, whereas ‘mapM’ is based on the Monad type class, it is possible to define ‘mapM’ as ‘traverse’ because every Monad is also an Applicative.
|
#173 |
![slide 173](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-173.png) |
- In Cats, ‘traverse’ is also defined in Traverse (aka Traversable).
|
#174 |
![slide 174](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-174.png) |
- Using Cats, we can write ourselves some boilerplate Scala code (which you can ignore) to define ‘mapM’ in terms of ‘traverse’, for convenience.
|
#175 |
![slide 175](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-175.png) |
- I am not really that surprised that ‘mapM’ is just ‘traverse’, because in the red book, I have already had my mind blown twice, when I learned that ‘traverse’ is so generic, that it can be used to define both the ‘map’ function, and the ‘foldMap’ function that we saw earlier.
|
#176 |
![slide 176](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-176.png) |
|
#177 |
![slide 177](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-177.png) |
|
#178 |
![slide 178](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-178.png) |
- Let’s skip the following slides on the symmetry that exists in the interrelation of flatMap/foldMap/traverse and flatten/fold/sequence.
|
#179 |
![slide 179](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-179.png) |
|
#180 |
![slide 180](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-180.png) |
|
#181 |
![slide 181](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-181.png) |
|
#182 |
![slide 182](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-182.png) |
|
#183 |
![slide 183](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-183.png) |
|
#184 |
![slide 184](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-184.png) |
|
#185 |
![slide 185](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-185.png) |
|
#186 |
![slide 186](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-186.png) |
- Let’s look at an example of using ‘mapM’ when the monadic context is Option, i.e. ‘mapM’ may or may not return a result.
|
#187 |
![slide 187](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-187.png) |
|
#188 |
![slide 188](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-188.png) |
- If we look at the Scala code at the bottom of the slide, we see a function ‘convert’ that takes a char and, if it is a digit, converts it to an Int, so it returns an Optional Int.
- In the first assertion, one of the chars is not a digit, so at some point ‘convert’ returns a None, and so ‘mapM’ short-circuits, and also returns a None.
- In the second assertion, all chars are digits, so ‘convert’ always returns a Some of an Int, and ‘mapM’, which is just ‘traverse’, i.e. it turns a List of Some of Int values inside out, into Some List of Int values.
|
#189 |
![slide 189](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-189.png) |
- Now let’s look at an example of using ‘mapM’ in which the monadic context is a List, i.e. ‘mapM’ returns zero, one or more results.
|
#190 |
![slide 190](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-190.png) |
|
#191 |
![slide 191](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-191.png) |
- We are all very familiar with the map function. If we take a list of strings “X” and “Y” and map over it this function, then the result is quite obvious…
|
#192 |
![slide 192](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-192.png) |
- First “X” is combined, first with “1”…
|
#193 |
![slide 193](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-193.png) |
|
#194 |
![slide 194](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-194.png) |
- …then “Y” is combined, first with “1”…
|
#195 |
![slide 195](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-195.png) |
|
#196 |
![slide 196](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-196.png) |
- But what happens when we use ‘mapM’ instead of ‘map’?
|
#197 |
![slide 197](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-197.png) |
- We are calling ‘mapM’ on List(“X”, “Y”), at the head of which is “X”…
|
#198 |
![slide 198](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-198.png) |
- … so “X” is passed to f, which returns List(“X1”,”X2”)…
|
#199 |
![slide 199](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-199.png) |
- …and in the for comprehension we choose the first element, i.e. “X1”…
|
#200 |
![slide 200](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-200.png) |
- …and then, in the for comprehension, we make a recursive call to ‘mapM’…
|
#201 |
![slide 201](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-201.png) |
- …which recursive call is on the tail of the list, at the head of which is “Y1”…
|
#202 |
![slide 202](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-202.png) |
- …so “Y1” is passed to f, which returns List(“Y1”,”Y2”)…
|
#203 |
![slide 203](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-203.png) |
- …and in the for comprehension we choose the first element, i.e. “Y1”…
|
#204 |
![slide 204](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-204.png) |
- …and then, in the for comprehension, we make a recursive call to ‘mapM’…
|
#205 |
![slide 205](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-205.png) |
- …which recursive call is the base case, so it returns a singleton List containing an empty list…
|
#206 |
![slide 206](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-206.png) |
- …so we come out of that recursive call…
|
#207 |
![slide 207](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-207.png) |
- …and in the for comprehension, we choose the first element, i.e. the empty List…
|
#208 |
![slide 208](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-208.png) |
- …and so the for comprehension conses “Y1” onto the empty list and yields the result…
|
#209 |
![slide 209](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-209.png) |
- …now in the for comprehension we switch to the second element, i.e. “Y2” and make a recursive call to ‘mapM’…
|
#210 |
![slide 210](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-210.png) |
- … which recursive call is again the base case…
|
#211 |
![slide 211](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-211.png) |
- …so when we come out of the recursive call, the result is the same singleton List containing an empty list…
|
#212 |
![slide 212](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-212.png) |
- …so in the for comprehension, we again choose the first element of the result list, i.e. an empty list…
|
#213 |
![slide 213](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-213.png) |
- …and the for comprehension then yields the result of consing “Y2” onto the empty list…
|
#214 |
![slide 214](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-214.png) |
- …we then come out of the first recursive call, and the result is List(List("Y1"),List("Y2"))…
|
#215 |
![slide 215](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-215.png) |
- …so in the for comprehension, we choose the first element of that result list, i.e. List(“Y1”)…
|
#216 |
![slide 216](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-216.png) |
- … and so, the for comprehension then conses “X1” onto List(“Y1”)), and this becomes the first value in our result.
- Now that you have seen how the sausage is made, I am just going to fast-forward through the rest of the computation.
|
#217 |
![slide 217](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-217.png) |
|
#218 |
![slide 218](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-218.png) |
|
#219 |
![slide 219](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-219.png) |
|
#220 |
![slide 220](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-220.png) |
|
#221 |
![slide 221](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-221.png) |
|
#222 |
![slide 222](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-222.png) |
|
#223 |
![slide 223](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-223.png) |
|
#224 |
![slide 224](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-224.png) |
|
#225 |
![slide 225](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-225.png) |
|
#226 |
![slide 226](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-226.png) |
- So, the result that we get when we use ‘mapM’, is quite different from the result that we got when using ‘map’. You can clearly see the effects of the List monad being hard at work combining things in as many different ways as possible.
|
#227 |
![slide 227](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-227.png) |
- I also have an example of using ‘mapM’ when the monadic context is the IO monad, but we don’t have time to go through it, so please look at it in your own time.
|
#228 |
![slide 228](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-228.png) |
|
#229 |
![slide 229](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-229.png) |
|
#230 |
![slide 230](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-230.png) |
|
#231 |
![slide 231](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-231.png) |
|
#232 |
![slide 232](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-232.png) |
|
#233 |
![slide 233](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-233.png) |
|
#234 |
![slide 234](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-234.png) |
|
#235 |
![slide 235](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-235.png) |
|
#236 |
![slide 236](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-236.png) |
|
#237 |
![slide 237](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-237.png) |
- That’s ‘mapM’ introduced.
|
#238 |
![slide 238](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-238.png) |
|
#239 |
![slide 239](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-239.png) |
- Now let’s introduce ‘filterM’.
|
#240 |
![slide 240](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-240.png) |
- I came across it in the same Haskell book.
|
#241 |
![slide 241](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-241.png) |
- What we want to do is understand how ‘filterM’works.
- We are going to look at the Scala code for it, which we can write ourselves using the Cats Monad type class.
|
#242 |
![slide 242](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-242.png) |
- Actually, to help understand how ‘filterM’works, let’s compare its code with that of ‘mapM’.
|
#243 |
![slide 243](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-243.png) |
- While ‘mapM’ takes a function f from A to B in a monadic context…
|
#244 |
![slide 244](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-244.png) |
- …the function passed to ‘filterM’ is called p, for predicate, and while it also takes an A, it returns a Boolean in a monadic context…
|
#245 |
![slide 245](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-245.png) |
- …and where ‘mapM’ obtains a B from the call to ‘f’, and a list of Bs from the recursive call to ‘mapM’, and yields the result of consing the B onto the Bs…
|
#246 |
![slide 246](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-246.png) |
- …‘filterM’ extracts from the call to ‘p’, a flag that tells it whether or not to retain the current element, and extracts from the recursive call to ‘filterM’ the list of elements retained so far, and so what ‘filterM’ does next is say: if I am keeping the current element, then I am returning the result of consing that element onto the list of elements retained so far, otherwise I am just returning the list of elements retained so far.
|
#247 |
![slide 247](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-247.png) |
- So where does ‘filterM’ live in Scala?
|
#248 |
![slide 248](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-248.png) |
- In Cats, in TraverseFilter, we can find a ‘filterA’ function that is based on Applicative.
|
#249 |
![slide 249](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-249.png) |
- Using Cats, we can write ourselves some boilerplate code (which you can ignore), to define ‘filterM’ in terms of ‘filterA, for convenience.
|
#250 |
![slide 250](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-250.png) |
- And now let’s look at an example of using ‘filterM’ when the monadic context is Option.
|
#251 |
![slide 251](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-251.png) |
|
#252 |
![slide 252](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-252.png) |
- In the bottom left corner of the slide, we see the Scala code for the ‘mapM’ example that we saw earlier…
|
#253 |
![slide 253](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-253.png) |
- Let’s adapt that code so that it serves as an example of using ‘filterM’.
- In the bottom right corner we see a function called ‘maybeIsEven’, which takes a char and, if it is a digit, converts it to an integer, and then checks whether or not the integer is even, so it returns an Optional Boolean.
- In the first assertion, one of the chars is not a digit, so at some point ‘maybeIsEven’ returns a None, and so ‘filterM’ short-circuits, and also returns a None.
- In the second assertion, all chars are digits, so ‘maybeIsEven’ always returns a Some of a flag: Some of false, Some of true, Some of false, Some of true, so what ‘filterM’ does is peer into the Optional values to access the flags and determine which elements of the List to keep.
|
#254 |
![slide 254](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-254.png) |
- Now let’s look at an example of using ‘filterM’ where the monadic context is a List.
|
#255 |
![slide 255](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-255.png) |
|
#256 |
![slide 256](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-256.png) |
- It turns out that if you pass ‘filterM’ a function that ignores its parameter and always returns a list containing both true and false (in other words, I want to eat my cake, and eat it too: I want to both keep the current element and not keep it), then ‘filterM’ returns the list of all the sub-lists of the input list. i.e. it computes the powerset function: the set of all subsets of a set.
|
#257 |
![slide 257](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-257.png) |
- Let’s see an example.
- If we filter the empty list, then that is the base case…
|
#258 |
![slide 258](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-258.png) |
- …the powerset of the empty list contains just the empty list itself…
|
#259 |
![slide 259](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-259.png) |
- If we filter a singleton list containing the element 3, then ‘filterM’ builds upon the elements of the powerset for the empty list (i.e. just the empty list), by both consing 3 onto them…
|
#260 |
![slide 260](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-260.png) |
- …and not consing 3 onto them…
|
#261 |
![slide 261](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-261.png) |
- … which results in a new powerset containing two lists…
|
#262 |
![slide 262](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-262.png) |
- …and if we filter a list with one more element, e.g. 2, then ‘filterM’ builds upon the elements of the powerset for the singleton list, by both consing 2 onto them…
|
#263 |
![slide 263](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-263.png) |
|
#264 |
![slide 264](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-264.png) |
- …and not consing 2 onto them…
|
#265 |
![slide 265](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-265.png) |
|
#266 |
![slide 266](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-266.png) |
- … which results in a new powerset containing four lists…
|
#267 |
![slide 267](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-267.png) |
- …and so on, and yes, we can see that when we filter a list with elements 1, 2 and 3, ‘filterM’ does indeed compute the powerset for that list.
|
#268 |
![slide 268](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-268.png) |
|
#269 |
![slide 269](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-269.png) |
|
#270 |
![slide 270](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-270.png) |
|
#271 |
![slide 271](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-271.png) |
|
#272 |
![slide 272](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-272.png) |
|
#273 |
![slide 273](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-273.png) |
|
#274 |
![slide 274](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-274.png) |
|
#275 |
![slide 275](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-275.png) |
|
#276 |
![slide 276](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-276.png) |
- That’s ‘filterM’ introduced.
|
#277 |
![slide 277](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-277.png) |
|
#278 |
![slide 278](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-278.png) |
- Now let’s introduce ‘foldM’.
|
#279 |
![slide 279](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-279.png) |
- We are all very familiar with the left fold, which applies a binary operator to an initial value and all the elements of a collection, going from left to right.
|
#280 |
![slide 280](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-280.png) |
- Here is a simple example in which we fold a list of integers using zero as the initial value and integer addition as the binary operator, so the result is 14, i.e. the sum of the integers.
|
#281 |
![slide 281](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-281.png) |
- We want to understand how ‘foldM’ works, so let’s compare the signature of a left fold with that of ‘foldM’.
- While the binary function passed to a left fold returns an A, the binary function passed to ‘foldM’ also returns an A, but in a monadic context…
|
#282 |
![slide 282](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-282.png) |
- While the overall result of a left fold is an A, the overall result of ‘foldM’ is also an A, but in a monadic context.
|
#283 |
![slide 283](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-283.png) |
- In Scala, we can find ‘foldM’ in Cats, in the Foldable type class.
|
#284 |
![slide 284](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-284.png) |
- Let’s look at an example of using ‘foldM’ where the monadic context is Option, i.e. ‘foldM’ may or may not return a result.
|
#285 |
![slide 285](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-285.png) |
|
#286 |
![slide 286](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-286.png) |
- If we look at the bottom of the slide, at the Scala code, we see a ‘binSmalls’ function that takes an accumulator and a current element, both integers.
- If the current element is too large, ‘binSmalls’ returns None, otherwise it adds the current element to the accumulator, and returns the result in a Some.
- In the first assertion, one of the integers in the list is too large, so at some point, ‘binSmalls’ returns None, and so ‘foldM’ short-circuits and also returns None.
- In the second assertion, all the elements in the list are small, so ‘binSmalls’ always returns a Some of an integer, and so ‘foldM’, which is passed an initial accumulator of zero, peers into the Optional values, to obtain the integer elements of the list, and add them to the accumulator, thus summing up the integers, and returning the same value that a left fold would compute, i.e. 14, but wrapped in a Some.
|
#287 |
![slide 287](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-287.png) |
- That example, in which the function passed to ‘foldM’ returns an Optional value, is easy to understand.
- It gets harder to understand, when the function passed to ‘foldM’ returns a list of values.
- But that is exactly how we need to use ‘foldM’ in order to solve the N-Queens puzzle, so in the upcoming slides, we are going to look at three examples that do just that.
- Before we do that though, let’s take another look at the definition of ‘foldM’.
|
#288 |
![slide 288](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-288.png) |
|
#289 |
![slide 289](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-289.png) |
|
#290 |
![slide 290](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-290.png) |
|
#291 |
![slide 291](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-291.png) |
|
#292 |
![slide 292](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-292.png) |
|
#293 |
![slide 293](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-293.png) |
- Let’s look at the pseudocode in the central rectangle, the one with the bright white background.
- The ‘foldM’ function takes a binary function that returns its result in a monadic context, an initial accumulator, and a list of elements.
- What it does is repeatedly invoke the binary function with the current accumulator and the current list element, each time extracting a new accumulator value from the resulting monadic context.
- It keeps doing that until it gets to the last list element, at which point it invokes the binary function one last time, and this time simply returns the function’s result, which is in a monadic context, since that is what ‘foldM’ does: it returns a result in a monadic context.
|
#294 |
![slide 294](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-294.png) |
|
#295 |
![slide 295](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-295.png) |
|
#296 |
![slide 296](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-296.png) |
|
#297 |
![slide 297](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-297.png) |
- Now let’s look at an example of using ‘foldM’ where the monadic context is a List.
- The thing to focus on, in order to understand the upcoming slides, is that while an ordinary fold manages one accumulator, in this example, ‘foldM’ manages zero, one, or more accumulators.
|
#298 |
![slide 298](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-298.png) |
|
#299 |
![slide 299](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-299.png) |
|
#300 |
![slide 300](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-300.png) |
|
#301 |
![slide 301](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-301.png) |
|
#302 |
![slide 302](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-302.png) |
- In our first example, we are going to pass ‘foldM’ a very unlikely function which ignores its two parameters, the accumulator and the current element, and always returns a list with two accumulators, both zero. When we fold an empty list, ‘foldM’ just returns the initial accumulator in a list (in this example the accumulator happens to be 9).
|
#303 |
![slide 303](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-303.png) |
- When we fold a non-empty list, ‘foldM’ invokes the given function with each of the current accumulators.
- When the list is a singleton, ‘foldM’ calls the given function once (with the initial accumulator), which results in a list of two accumulators.
|
#304 |
![slide 304](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-304.png) |
- When we fold a list with one more element, ‘foldM’ builds on those two accumulators by invoking the given function once for each of the accumulators, which results in two lists of two accumulators, which get flatMapped into a list of four accumulators.
|
#305 |
![slide 305](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-305.png) |
- When we fold a list with one more element, ‘foldM’ builds on those four accumulators by invoking the given function once for each of the accumulators, which results in four lists of two accumulators, which get flatMapped into a list of eight accumulators.
|
#306 |
![slide 306](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-306.png) |
- And so on.
- As you can see, the number of accumulators doubles with each iteration, so the number of accumulators in the result list is two to the power of the length of the list being folded.
|
#307 |
![slide 307](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-307.png) |
|
#308 |
![slide 308](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-308.png) |
|
#309 |
![slide 309](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-309.png) |
|
#310 |
![slide 310](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-310.png) |
|
#311 |
![slide 311](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-311.png) |
- In the second example, we change the function that we pass to ‘foldM’ so that it is a bit more realistic, a bit more useful.
- Instead of ignoring its accumulator and current element parameters, the function both adds the current element to the accumulator and subtracts it from the accumulator, returning a two-element list containing both the result of the addition and the result of the subtraction.
|
#312 |
![slide 312](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-312.png) |
|
#313 |
![slide 313](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-313.png) |
|
#314 |
![slide 314](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-314.png) |
- Here is how the computation unfolds, visually. You can see that ‘foldM’ is using the given function to add/subtract the current element to/from the accumulator.
- You can also see that just like in the previous example, the number of accumulators doubles with each iteration.
- By the way, the first and last of the values in the result list are the values that would be computed by a plain left fold, using addition and subtraction respectively, as the binary operation.
|
#315 |
![slide 315](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-315.png) |
|
#316 |
![slide 316](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-316.png) |
|
#317 |
![slide 317](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-317.png) |
|
#318 |
![slide 318](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-318.png) |
|
#319 |
![slide 319](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-319.png) |
- In our third example, we change the type of the accumulator from integer to list, and we change the function passed to ‘foldM’ so that rather than adding and subtracting the current element from the accumulator, it both conses the current element onto the accumulator, and refrains from consing the element onto the accumulator.
|
#320 |
![slide 320](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-320.png) |
|
#321 |
![slide 321](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-321.png) |
|
#322 |
![slide 322](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-322.png) |
- Here is how the computation unfolds visually.
- You can see that in each iteration, the function is both consing, and refraining from consing, the current element onto the current accumulators.
- As in the previous two examples, the number of accumulators is again doubling with each iteration.
|
#323 |
![slide 323](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-323.png) |
- It turns out that given this particular function, ‘foldM’ computes the powerset of the input list. So we found another way of computing the powerset.
|
#324 |
![slide 324](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-324.png) |
|
#325 |
![slide 325](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-325.png) |
- That’s ‘foldM’ introduced.
|
#326 |
![slide 326](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-326.png) |
|
#327 |
![slide 327](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-327.png) |
- Now that we understand how ‘foldM’ works, let’s see how we can use it to solve the N-Queens combinatorial puzzle.
|
#328 |
![slide 328](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-328.png) |
- We are going to use ‘foldM’ to generate the permutations of a list of integers, namely the column numbers where we can try to place a queen.
|
#329 |
![slide 329](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-329.png) |
- We already have a function that computes the permutations of columns 1,2,3,4.
- But this function allows repetition (i.e. repeating column numbers - multiple queens allowed in the same column).
|
#330 |
![slide 330](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-330.png) |
- But what we want to compute are the permutations without allowing repetition.
- i.e. if we have numbers 1,2,…N, we want to compute N! (N factorial) permutations, e.g. for N=3, we want to compute 3! = 3 x 2 x 1 = 6 permutations.
- Notice how no digit is ever repeated in a permutation.
|
#331 |
![slide 331](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-331.png) |
|
#332 |
![slide 332](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-332.png) |
|
#333 |
![slide 333](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-333.png) |
- We can compute such permutations by passing to ‘foldM’ this update function.
- The function takes two parameters. The second parameter, i.e. the current element of the list, is ignored.
- The first argument, i.e. the accumulator, is a pair consisting of (1) a partial permutation computed so far, and (2) a list of choices still available.
- For each of the available choices, the update function generates a new accumulator whose permutation is arrived at by consing the selected choice onto the partial permutation, and whose choices are arrived at by removing the selected choice from the available choices.
- Notice how that means that each time the update function is invoked, a partial permutation is grown into one or more fuller permutations, and a list of available choices is shrunk into one or more lists of choices with one less available choice.
|
#334 |
![slide 334](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-334.png) |
- And that works: if we pass the update function to ‘foldM’, with an initial accumulator consisting of the empty permutation as the initial partial permutation, and the list of column numbers to be permuted as the initial list of choices, and if we then specify this same list as the input list to be folded, then ‘foldM’ does indeed compute the permutations.
- Or rather, it computes a list of pairs, each of which contains one of the permutations, together with some noise in the form of an empty list (we will soon see how to deal with that).
- Also, notice that the actual content of the input list doesn’t matter, only its length does, as it determines the number of iterations performed by ‘foldM’.
- For convenience, we use as an input list the same list whose items we want to permute, e.g. 1,2,3.
|
#335 |
![slide 335](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-335.png) |
|
#336 |
![slide 336](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-336.png) |
|
#337 |
![slide 337](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-337.png) |
|
#338 |
![slide 338](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-338.png) |
- Here is how the computation unfold visually. You can see that this time, the number of accumulators does not double every time.
- Rather, it grows in a way that reflects the computation of N!.
- In each iteration ‘foldM’ has to choose an integer for each of the current accumulators.
- In the first iteration, there is one accumulator with three integers to choose from, so ‘foldM’ generated 3 x 1 = 3 accumulators.
- In the next iteration, for each of those three accumulators, ‘foldM’ has to choose an integer, with two integers to choose from, so ‘foldM’ generated 3 x 2 = 6 accumulators.
- In the last iteration, for each of those six accumulators, ‘foldM’ has to choose an integer, with only one choice available, so ‘foldM’ generated 6 x 1 = 6 accumulators.
- So the number of accumulators is 3! = 3 x 2 x 1 = 6.
|
#339 |
![slide 339](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-339.png) |
- As mentioned before, while the result returned by ‘foldM’ includes the desired permutations, it also contains some noise in that each permutation is part of a pair that also contains an empty list.
- Let’s skip the following slides about the boilerplate code needed to strip out the noise.
|
#340 |
![slide 340](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-340.png) |
|
#341 |
![slide 341](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-341.png) |
|
#342 |
![slide 342](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-342.png) |
|
#343 |
![slide 343](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-343.png) |
- Our domain is the N-Queens puzzle, so let’s do some renaming to reflect that.
- Let’s rename the ‘update’ function to ‘oneMoreQueen’. Let’s also rename ‘permutation’, the partial permutation generated so far, to ‘queens’, the columns in which we have already placed queens.
- And let’s rename ‘choices’, the elements which we are still able to pick in the process of creating a permutation, to ‘emptyColumns’, the columns where we still have the choice of trying to place a queen.
|
#344 |
![slide 344](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-344.png) |
- While we are able to use ‘foldM’ to generate permutations without repetition, we are only interested in safe permutations, so let’s use the ‘isSafe’ function to filter out unsafe permutations.
|
#345 |
![slide 345](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-345.png) |
- Here is how we invoked ‘foldM’ earlier, when generating the permutations for 1,2,3.
|
#346 |
![slide 346](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-346.png) |
- But what we need to do now is write a function ‘queens’ that takes integer N, and returns the safe permutations for 1,2,…,N, e.g. for N=4 there are two such permutations.
|
#347 |
![slide 347](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-347.png) |
- So given that we have renamed ‘update’ to ‘oneMoreQueen’, is how we now need to invoke ‘foldM’.
|
#348 |
![slide 348](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-348.png) |
- And finally, as mentioned before, we need to strip out noise from the result of ‘foldM’, so let’s do that by mapping over the result with a function that replaces each pair with its head, which is a permutation, so that the result is mapped to a list of permutations.
|
#349 |
![slide 349](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-349.png) |
- And we are done. Here is the code, both in Haskell and in Scala, for the iterative solution to the N-Queens puzzle, using ‘foldM’.
- Also included, for completeness, is the ‘isSafe’ function, which we are not going to discuss any further.
|
#350 |
![slide 350](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-350.png) |
- We have gone from a recursive algorithm to an iterative one.
|
#351 |
![slide 351](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-351.png) |
- Here is the recursive code for both Scala and Haskell (ignore the fact that I have refactored the ‘isSafe’ function and its helper functions).
|
#352 |
![slide 352](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-352.png) |
- Here is the transition we have gone through in Haskell.
|
#353 |
![slide 353](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-353.png) |
- And here is the original Haskell code, from the Rosetta Code site, which gave me the idea for this talk.
- You can see that it includes quite a few comments, because understanding it is hard without comments.
- It is still not easy, even with comments, especially for people who are new to ‘foldM’. Below is our current version of the code.
- I have omitted any comments because we are now very familiar with its workings.
- I believe our renaming of variables in ‘oneMoreQueen’ makes the latter easier to understand.
|
#354 |
![slide 354](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-354.png) |
- Here is the transition we have gone through in Scala.
|
#355 |
![slide 355](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-355.png) |
|
#356 |
![slide 356](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-356.png) |
|
#357 |
![slide 357](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-357.png) |
|
#358 |
![slide 358](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-358.png) |
- To conclude this talk, I want to point out that one way in which the iterative algorithm differs from the recursive one, results in the iterative algorithm doing less work.
- Because the recursive algorithm does not remember where it has already placed previous queens, it will happily generate, and then test for safety, a candidate board that is obviously unsafe, because it contains two queens in the same column.
- The iterative algorithm, on the other hand, does remember where it has already placed previous queens.
- The number of columns still available in the ‘emptyColumns’ argument of the ‘oneMoreQueens’ function, shrinks over time to reflect attempts to place queens in available columns.
|
#359 |
![slide 359](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-359.png) |
|
#360 |
![slide 360](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-360.png) |
|
#361 |
![slide 361](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-361.png) |
|
#362 |
![slide 362](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-362.png) |
|
#363 |
![slide 363](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-363.png) |
|
#364 |
![slide 364](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-364.png) |
|
#365 |
![slide 365](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-365.png) |
|
#366 |
![slide 366](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-366.png) |
|
#367 |
![slide 367](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-367.png) |
|
#368 |
![slide 368](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-368.png) |
|
#369 |
![slide 369](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-369.png) |
|
#370 |
![slide 370](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-370.png) |
|
#371 |
![slide 371](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-371.png) |
|
#372 |
![slide 372](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-372.png) |
|
#373 |
![slide 373](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-373.png) |
|
#374 |
![slide 374](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-374.png) |
|
#375 |
![slide 375](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-375.png) |
|
#376 |
![slide 376](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-376.png) |
|
#377 |
![slide 377](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-377.png) |
|
#378 |
![slide 378](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-378.png) |
|
#379 |
![slide 379](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-379.png) |
|
#380 |
![slide 380](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-380.png) |
- Let’s concentrate on the right-hand side of this table.
- It shows that when N=4, the recursive algorithm generates 60 boards, of which 16 are candidate boards, i.e. they contain the requisite number of queens (4 in this case).
- The iterative algorithm, on the other hand, generates 32 boards (about half the number), of which 4 are candidate boards (a quarter).
- So, the iterative algorithm does less work.
|
#381 |
![slide 381](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-381.png) |
- This difference persists and widens as N grows.
- For N=8, for example, the recursive algorithm generates over 15,718 boards, whereas the iterative algorithm generates 5,506 (about a third).
- As for candidate boards, the recursive algorithm generates 2,495 boards, whereas the iterative one generates 312 (almost a tenth).
|
#382 |
![slide 382](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-382.png) |
|
#383 |
![slide 383](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-383.png) |
|
#384 |
![slide 384](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-384.png) |
- Here is how the number of boards generated by the two algorithm compares as N grows from 4 to 8.
|
#385 |
![slide 385](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-385.png) |
- And here is the same illustration but for candidate boards.
|
#386 |
![slide 386](https://fpilluminated.s3.eu-west-2.amazonaws.com/slide-decks/2023-08-03-n-queens-combinatorial-puzzle-meets-cats/slides/png/2023-08-03-n-queens-combinatorial-puzzle-meets-cats-386.png) |
|