úÎ!º“³oq      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQ R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p None,-.456=>?@AHMUVXk§1 None,-.456=>?@AHMUVXkÀNone,-.456=>?@AHMUVXk;gridsPRepresents valid dimensionalities. All non empty lists of Nats have an instance gridsGet the total size of a Grid of the given dimensions gridSize (Proxy @'[2, 2]) == 4 gridsaComputes the level of nesting requried to represent a given grid dimensionality as a nested list HNestedLists [2, 3] Int == [[Int]] NestedLists [2, 3, 4] Int == [[[Int]]]   None%&',-.1456=>?@AHMUVXgkgridsThe index type for Grids.gridsSafely construct a ? for a given grid size, checking that all indexes are in range h»> coord @[3, 3] [1, 2] Just [1, 2] »> coord @[3, 3] [3, 3] Nothing »> coord @[3, 3] [1, 2, 3] NothinggridsGet the first index from a grids Append two s  None,-.456=>?@AHMUVXkB%&%&None,-.456=>?@AHMUVXk.Ž ,grids An grid of arbitrary dimensions.e.g. a Grid [2, 3] Int might look like: Rgenerate id :: Grid [2, 3] Int fromNestedLists [[0,1,2], [3,4,5]]0grids5Build a grid by selecting an element for each element1gridsTTurn a grid into a nested list structure. List nesting increases for each dimension BtoNestedLists (G.generate id :: Grid [2, 3] Int) [[0,1,2],[3,4,5]]2gridsyTurn a nested list structure into a Grid if the list is well formed. Required list nesting increases for each dimension ™fromNestedLists [[0,1,2],[3,4,5]] :: Maybe (Grid [2, 3] Int) Just (Grid [[0,1,2],[3,4,5]]) fromNestedLists [[0],[1,2]] :: Maybe (Grid [2, 3] Int) Nothing3gridsPartial variant of 2 which errors on malformed input4gridsRConvert a list into a Grid or fail if not provided the correct number of elements ‘G.fromList [0, 1, 2, 3, 4, 5] :: Maybe (Grid [2, 3] Int) Just (Grid [[0,1,2],[3,4,5]]) G.fromList [0, 1, 2, 3] :: Maybe (Grid [2, 3] Int) Nothing5gridsPartial variant of 4 which errors on malformed input6gridsUpdate elements of a grid7gridsThe inverse of 8[, joinGrid will nest a grid from: > Grid outer (Grid inner a) -> Grid (outer ++ inner) aIFor example, you can nest a simple 3x3 from smaller [3] grids as follows: <joinGrid (myGrid :: Grid [3] (Grid [3] a)) :: Grid '[3, 3] a8gridsThe inverse of 7, splitGrid  outerDims [innerDims will un-nest a grid from: > Grid (outer ++ inner) a -> Grid outer (Grid inner a)4For example, you can unnest a simple 3x3 as follows: 6splitGrid @'[3] @'[3] myGrid :: Grid '[3] (Grid [3] a) *+,-./012345678,-./ 0123456*+78None,-.456=>?@AHMSUVXk0¥JgridsFocus an element of a , given its GHIJHGIJNone%*,-.456;<=>?@AHMUVXkPXKgridsÁPerform a computation based on the context surrounding a cell Good for doing things like Linear Image Filters (e.g. gaussian blur) or simulating Cellular Automata (e.g. Conway's game of life)BThis function accepts a function which indicates what to do with 'out-of-bounds' indexes,  clampWindow,  wrapWindow and  safeWindow are examples.¯It also acccepts a transformation function which operates over the functor created by the first parameter and collapses it down to a new value for the cell at that position.ÅThis function is best used with Type Applications to denote the desired window size; the Grid passed to the given function contains the current cell (in the middle) and all the surrounding cells.–Here's an example of computing the average of all neighboring cells, repeating values at the edge of the grid when indexes are out of bounds (using  clampWindow) Âgaussian :: (IsGrid dims) => Grid dims Double -> Grid dims Double gaussian = autoConvolute clampBounds avg where avg :: Grid '[3, 3] Double -> Double avg g = sum g / fromIntegral (length g)Lgrids#This is a fully generic version of K˜ which allows the user to provide a function which builds a context from the current coord, then provides a collapsing function over the same functor.Mgrids+Given a coordinate generate a grid of size MM filled with coordinates surrounding the given coord. Mostly used internallyNgrids Use with KA; Clamp out-of-bounds coordinates to the nearest in-bounds coord.Ogrids Use with KL; Wrap out-of-bounds coordinates pac-man style to the other side of the gridPgrids Use with K; Out of bounds coords become qKgrids4Restrict out of bounds coordinates in some way. Use  clampWindow,  wrapWindow or  safeWindowgrids$Collapse the context down to a valuegrids Starting gridLgridsCBuild a neighboring context within a functor from the current coordgrids&Collapse the context to a single valuegrids Starting grid*KLMNOPKLNOPM* None%,-.456;<=>?@AHMUVXkQ†QRSSRQ None,-.456=>?@ACHMUVXk_±Vgrids9Get the inverse of a permutation pattern, used internallyYgridsPermute dimensions of a ,/. This is similar to MatLab's permute functionYi requires a type application containing a permutation pattern; The pattern is a re-ordering of the list [0..n]P which represents the new dimension order. For example the permutation pattern  [1, 2, 0]! when applied to the dimensions  [4, 5, 6] results in the dimensions  [5, 6, 4].0For 2 dimensional matrixes, a permutation using [1, 0] is simply a matrix [ †»> small fromNestedLists [[0,1,2] ,[3,4,5] ,[6,7,8]] »> permute @[1, 0] small fromNestedLists [[0,3,6] ,[1,4,7] ,[2,5,8]]ZgridsPPermute the dimensions of a coordinate according to a permutation pattern. see Y regarding permutation patterns[grids0Transpose a 2 dimensional matrix. Equivalent to: permute @[1, 0]VWXYZ[XWYZ[VNone,-.456=>?@AHMUVXk`·) *,-./012345678JKLMNOPRSWXYZ[),-.0234516JKLMSRNOP[YZ78/ *WX None,-.456=>?@AHMUVXkbÕ\]^_`abcdefghijk\]^_`abcdefghijk None %,-.456=>?@AHMUVXk²Dlgrids#Conway's game of life is a form of  0https://en.wikipedia.org/wiki/Cellular_automatonCellular AutomataY; This means that it's a system of cells where a simulation is described in terms of the  neighbourhoodg of a cell. We'll implement the standard set of rules for Conway's Game of Life using convolution with grids) (which you can read about on wikipedia)!grids provides the L and KW helpers to allow performing neighbourhood-aware computations without too much trouble.Kÿl allows you to provide a window-size via a Type Application, a function for adapting the coordinates of the neighbours, which is useful for providing behaviour for cases where coordinates are out of bounds. Lastly we provide a function which can reduce the provided neighbourhood of a cell back down to a single cell which will be slotted into the final structure.(With these things in mind, we write our l7 function which performs a single simulation step on a ,5 using a window-reduction rule that we'll write next! fstep :: (IsGrid dims) => Grid dims Bool -> Grid dims Bool step = autoConvolute @[3, 3] wrapBounds rule We use the Oˆ strategy for handling out-of-bounds indices which will occur when trying to get the neighbourhood of cells along the edge of the grid. Oa means we'll grab the next cell from the opposite side of the grid, wrapping around Pacman style.mgridsþNext up we'll write the reduction rule itself. We've already decided to use a [3, 3] neighbourhood in the previous step by using a Type Application, GHC could infer it in thi case if we didn't provide it; but I find it helpful to be as clear as possible.wSo the goal is to go from a [3, 3] neighbourhood of a cell down to a single cell again; the liveness of each cell is a r which is s if the cell is alive, t otherwise.Take a look at how we do it: ÿrule :: Grid [3, 3] Bool -> Bool rule window' = (currentCellAlive && livingNeighbours == 2) || livingNeighbours == 3 where (currentCellAlive, neighbours) = partitionFocus window' livingNeighbours = length . filter id . toList . Compose $ neighboursWe'll start with the where clauses.Firstly we use the nifty S„ combinator which separates out the center of a window from the surrounding neighbours as a tuple. Intuitively, We name these parts currentCellAlive and  neighboursI. Next we count how many neighbours are actually alive by leaning on the u typeclass. S returns the neighbours as a Grid [3, 3] (Maybe Bool)& in this case; so by wrapping it with v we can fold over only the w5 values, e.g. the neighbours! We then filter out the t ones with  filter id+ and we know how many neighbours are alive!¯Back to the main definition, all that's left is to write the actual logic of the rule; there are many ways to write in the rule; but I hope you trust I've picked a good one :DžThat's it! By combining our rule with the powers of auto-convolution we've written the core of Conway's game of life in just a dozen lines of code. Clever us!JKeep reading and we'll add some helpers so we can actually try running it.ngridsFIf we're going to simulate a game we need to have a starting position!ALet's start off with a glider hanging out in the top left corner.\Since we'll be using a 2 dimensional grid we can draw out our grid as a list of lists (i.e. [String] ) and use 3 to build it into a , for us! Note that the trailing ' denotes the unsafe version of 2• which will error if we give it input that mismatches our expected dimensions, use the safe version unless you're confident about your input sources! ðstart :: Grid '[10, 10] Bool start = (== '#') <$> fromNestedLists' [ ".#........" , "..#......." , "###......." , ".........." , ".........." , ".........." , ".........." , ".........." , ".........." , ".........." ]ogridsjNow that we've got a good starting point we can run a few steps of our simulation and see where we end up!lQ is an Endomorphisn, i.e. a function from a type to the same type, so we can use x[ to generate an infinite list of steps where each subsequent step is equal to applying the l$ function on the previous iteration. By using yd we can index into the infinite list and see what things look like after a set number of iterations. Ksimulate :: Int -> Grid '[10, 10] Bool simulate i = iterate step start !! ipgridsThe built-in show instance for ,l isn't perfect, so let's write a nice one for our simulation. We can extract our grid as a list of lists of Bool, i.e. [[Bool]]B; and collapse it into a string so we can print it to the console. ÍshowGrid :: (IsGrid '[x, y]) => Grid '[x, y] Bool -> String showGrid = intercalate "\n" . toNestedLists . fmap showBool where showBool :: Bool -> Char showBool True = '#' showBool False = '.';Let's how far our glider can make it to after 10 iterations ’»> putStrLn . showGrid $ simulate 10 .......... .......... .......... ....#..... ..#.#..... ...##..... .......... .......... .......... ..........!That's it for this guide! Thanks!lmnoplmnopNone,-.456=>?@AHMUVXk³Jz{|}~€‚ !"##$%&'()*+,-./0123456789:;<=>>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~  € ‚ƒ„…†„…‡„…ˆ‰Š‹Œ‚ŽŽ‘’“”•–—˜™$grids-0.5.0.1-HkiIr1Gao1S6exXk40fBoLData.Grid.Internal.Errors Data.GridData.Grid.Internal.NestedListsData.Grid.Internal.CoordData.Grid.Internal.PrettyData.Grid.Internal.GridData.Grid.Internal.LensData.Grid.Internal.ConvolutionData.Grid.Internal.ShapesData.Grid.Internal.TransposeData.Grid.Examples.IntroData.Grid.Examples.ConwayData.Grid.Internal.Nest Paths_gridsbase GHC.TypeLitsText:<>::$$:ShowType&adjunctions-4.4-J8nZ5egZ0xU2d8YwbV1sWVData.Functor.Repindextabulate ErrorMessage?!Sizable nestLists unNestListsgridSize NestedLists chunkVector $fSizable: $fSizable:0CoordunCoord:#coordunconsCappendC highestIndexclamp clampCoord wrapCoordcoerceCoordDims coordInBounds $fEnumCoord $fEnumCoord0$fBoundedCoord$fBoundedCoord0 $fNumCoord $fIsListCoord $fEqCoord $fShowCoord PrettyList prettyList$fPrettyList[]$fPrettyList[]0$fPrettyList[]1 NeighboringneighborCoordsGridtoVectorIsGridgenerate toNestedListsfromNestedListsfromNestedLists'fromList fromList'//joinGrid splitGrid$fNeighboring:$fNeighboring:0 $fNumGrid$fRepresentableGrid$fDistributiveGrid$fApplicativeGrid $fMonoidGrid$fSemigroupGrid $fShowGrid$fEqGrid $fFunctorGrid$fFoldableGrid$fTraversableGrid $fNFDataGridLens'Lenslenscell autoConvolute convolutewindow clampBounds wrapBounds omitBoundsCentered centerCoordpartitionFocus $fCentered: $fCentered:0 InvertKeyValidPermutationPermutedpermute permuteCoord transpose simpleGrid coordGridavgmx verySmallsmallsmall'medbiggauss clampGaussseeNeighboringcoords doubleGrid simpleGauss pacmanGausssteprulestartsimulateshowGrid GHC.MaybeNothingghc-prim GHC.TypesBoolTrueFalse Data.FoldableFoldableData.Functor.ComposeComposeJustGHC.Listiterate!!version getBinDir getLibDir getDynLibDir getDataDir getLibexecDir getSysconfDirgetDataFileName