public Maybe <BasicImage> WithKernelApplied(
            double[][] kernel,
            Action <double> onProgressChanged,
            LightSwitch continuation
            )
        {
            var result   = Clone();
            var lastPart = BytesPerPixel == 3 ? ColourPart.Blue : ColourPart.Alpha;

            var checkpoint = DateTime.Now;

            for (int index = 0; index < Height; index++)
            {
                for (int jndex = 0; jndex < Width; jndex++)
                {
                    for (var part = ColourPart.Red; part <= lastPart; part++)
                    {
                        var address = new ImageAddress(index, jndex, part);
                        result[index, jndex, part] = ComputeNewPixelValue(kernel, address).AbsToByte();
                        if (!continuation.IsActive)
                        {
                            return(new Nothing <BasicImage>());
                        }
                    }

                    checkpoint = ReportProgress(onProgressChanged, checkpoint, index, jndex);
                }
            }

            onProgressChanged(100);
            return(new Just <BasicImage>(result));
        }
        double ComputeNewPixelValue(IReadOnlyList <IReadOnlyList <double> > kernel, ImageAddress address)
        {
            double    result     = 0;
            const int kernelSize = 3;

            for (int row = 0; row < kernelSize; row++)
            {
                for (int column = 0; column < kernelSize; column++)
                {
                    result += kernel[row][column] *
                              this[
                        address.Index - 1 + row,
                        address.Jndex - 1 + column,
                        address.ColourPart
                              ];
                }
            }

            return(result);
        }