:e TypeFamilies
:e GeneralizedNewtypeDeriving
:e DeriveTraversable
:e TypeSynonymInstances
:e FlexibleInstances
:e ApplicativeDo
:e LambdaCase
:e TupleSections
import Graphics.Gloss.Interface.IO.Simulate (simulateIO, Display (FullScreen))
import Graphics.Gloss (white, Picture (Text, Polygon, Color, Circle, Pictures), simulate, Rectangle (Rectangle), black, red, translate)
import Control.Monad.Bayes.Class (MonadDistribution(bernoulli, uniformD, random, normal), factor, MonadMeasure)
import Control.Monad.Bayes.Sampler.Strict (sampler, sampleIOfixed)
import Control.Monad.Bayes.Traced (mh, mhStep)
import Control.Monad.Bayes.Weighted
import Data.Functor.Compose (Compose(..))
import qualified Data.Vector as V
import Data.Bool (bool)
import Data.Distributive (Distributive(..))
import Data.Functor.Rep (Representable(..), distributeRep, ifoldMapRep)
import Data.Functor.Identity (Identity(..))
import Control.Arrow ((***), Arrow (first, second))
import Control.Comonad.Representable.Store (Store(..), StoreT(..), store, experiment, runStore)
import Control.Comonad (Comonad(..), (=>>))
import Graphics.Gloss.Data.Color (Color)
import Control.Monad (filterM)
import Debug.Trace (trace)
import Data.Monoid (Sum(Sum, getSum))
import Control.Monad.Bayes.Inference.SMC
import Control.Monad.Bayes.Population
import qualified Pipes.Prelude as P
import Pipes ((>->))
import Graphics.Gloss.Interface.IO.Animate (animateIO)
import Data.IORef (newIORef, writeIORef)
import GHC.IORef (readIORef)
import qualified Pipes as P
import Control.Concurrent (forkIO, threadDelay)
import Control.Monad.IO.Class
import Control.Monad.Bayes.Sampler.Strict
The Ising model is a famous model in statistical mechanics. See the wonderful https://jaan.io/how-does-physics-connect-machine-learning/. Basically, it's a big grid of squares, each of which can be in one of two states. We can assign an "interaction energy" between adjacent states, which says how much they like to be in similar or different states. A configuration of the whole grid (i.e. choosing a setting for each square) determines a global energy, and in turn, a distribution (the Boltzmann distribution) over grids.
The code borrows heavily from the excellent https://chrispenner.ca/posts/conways-game-of-life which uses a representable store comonad to perform efficient local updates to a grid. The approach should extend easily to similar models with different topologies.
------
-- Define a board as a length 20 array of length 20 arrays
-- Define a grid as a board and a pointer to a square
------
-- | Grid a ~ ([[a]], (Int, Int))
type Grid a = Store (Compose VBounded VBounded) a
type Table = Compose VBounded VBounded
-- | VBounded a ~ [a]
newtype VBounded a = VBounded (V.Vector a)
deriving (Eq, Show, Functor, Foldable, Traversable)
instance Distributive VBounded where
distribute = distributeRep
-- | size of the Ising grid
gridSize :: Int
gridSize = 40
-- | you can view a grid as a function from indices to square values
-- or as an array of square values.
-- These two structures are isomorphic, as witnessed by:
-- index . tabulate === id === tabulate . index
instance Representable VBounded where
type Rep VBounded = Int
index (VBounded v) i = v V.! (i `mod` gridSize)
tabulate desc = VBounded $ V.generate gridSize desc
-- | make a grid
mkGrid :: [(Int, Int)] -> Grid Bool
mkGrid xs = store (`elem` xs) (0, 0)
There are two ways we can simulate an Ising model. The first is to define a distribution over grids directly, by drawing from a uniform prior, and adding a factor statement for the energy. One can then sample from this distribution using MCMC, and indeed, the MCMC chain will look like a time-evolving Ising model. Which is very cool!
Let's do that first:
-- | calculate the energy of a particular square in the grid
-- (which depends on the rest of the grid, in particular its neighbours)
interactionEnergy :: Grid Bool -> Int
interactionEnergy g = numNeighboursSame
where
numNeighboursSame = length (filter (==color) neighbours)
color = extract g
neighbours = experiment (\s -> addCoords s <$> neighbourCoords) g
addCoords (x, y) (x', y') = (x + x', y + y')
neighbourCoords = [(x, y) | x <- [-1, 0, 1], y <- [-1, 0, 1], (x, y) /= (0, 0)]
-- | The prior is uniform over all configurations of the grid
-- We score states based on their energy
model :: MonadMeasure m => m (Grid Bool)
model = do
let allCoords = [(x,y) | x <- [0..gridSize-1], y <- [0..gridSize-1]]
coords <- filterM (const $ bernoulli 0.5) allCoords
let grid = mkGrid coords
StoreT (Identity energy) _ = extend interactionEnergy grid
score = getSum $ foldMap Sum energy
factor $ exp $ fromIntegral score
return grid
---
-- render a grid into ascii using an indexed fold
---
display :: Grid Bool -> String
display (StoreT (Identity grid) _) = ifoldMapRep match grid where
match (_,n) b
| n==0 = "\n|" <> showB b
| n==gridSize-1 = "|" <> showB b <> "|"
| otherwise = "|" <> showB b
showB True = "X"
showB False = "O"
samples = do
s <- sampler $ unweighted $ mh 2 model
mapM_ (\x -> putStrLn ("\n\n" <> display x)) $ reverse $ take 2 s
samples
|O|X|O|O|X|X|X|O|X|O|O|O|X|O|O|X|X|X|X|O|X|X|O|O|O|X|O|O|O|X|X|O|O|O|X|O|O|O|X|O| |O|O|X|X|O|O|O|O|X|O|O|X|X|X|X|X|X|O|X|O|O|X|X|X|X|X|X|O|X|X|X|X|O|O|X|X|O|O|X|X| |O|O|O|X|X|X|O|O|O|X|O|X|O|X|O|O|O|X|X|X|O|O|O|X|O|O|O|X|X|O|X|O|O|X|O|O|O|O|O|X| |O|O|X|O|O|X|O|O|O|O|X|X|O|O|X|O|O|O|X|O|X|O|O|X|O|X|X|O|X|X|O|O|X|X|X|X|O|O|O|O| |X|X|X|O|O|X|O|O|X|O|X|X|X|O|X|O|O|X|O|O|X|X|O|O|X|O|O|O|X|O|X|X|O|O|O|O|O|O|X|O| |O|O|X|X|O|O|X|X|X|O|O|X|O|X|X|O|O|O|X|O|X|O|O|X|X|X|O|X|X|O|O|O|O|O|X|O|O|O|X|O| |O|O|O|O|O|X|O|O|O|O|X|X|O|X|O|O|X|X|X|O|O|O|O|O|X|X|O|O|X|O|O|O|X|X|O|X|O|O|X|X| |X|O|O|O|X|O|O|X|O|O|O|O|X|O|O|X|O|X|X|X|X|O|O|X|O|X|O|O|X|X|O|O|O|X|O|X|X|X|X|X| |O|O|X|O|X|O|X|X|O|X|X|X|O|X|X|X|O|X|O|O|O|O|X|O|X|O|O|X|X|X|X|O|O|O|O|X|O|X|X|X| |O|O|X|X|X|O|O|X|O|O|X|X|O|O|O|X|O|X|X|X|X|O|X|X|X|X|X|X|O|X|X|X|X|X|O|X|O|O|X|X| |X|X|X|O|X|X|O|X|O|O|X|X|X|O|X|O|O|O|O|O|O|O|X|O|O|O|X|X|X|X|X|X|O|O|O|X|X|X|X|X| |O|X|O|O|X|O|X|X|X|X|O|X|X|X|X|X|X|X|O|O|O|O|X|O|O|X|X|O|O|O|X|X|X|O|X|O|X|O|O|O| |X|O|X|O|X|O|O|X|X|X|O|O|X|O|O|O|O|X|O|O|X|O|O|O|X|X|O|X|X|X|X|O|X|O|X|O|X|X|O|O| |X|O|X|O|O|O|O|X|O|X|O|O|O|X|X|O|O|X|O|O|O|X|O|X|X|X|X|O|X|O|O|O|O|O|X|O|O|O|X|X| |X|O|O|O|O|X|X|O|O|O|X|X|X|O|X|X|O|X|O|X|X|X|O|X|X|X|O|O|X|O|X|X|X|O|X|X|X|X|O|X| |X|O|O|O|O|O|X|O|O|X|X|O|O|O|O|X|X|O|X|X|O|X|X|X|X|X|X|X|O|O|O|X|X|X|O|O|O|O|O|X| |X|O|O|X|O|O|X|X|O|X|X|X|X|O|X|X|X|O|O|X|X|O|O|X|O|O|X|X|X|X|O|X|O|X|O|O|O|X|X|O| |X|X|X|X|O|X|O|O|O|X|O|X|O|O|X|O|O|O|X|X|X|O|X|X|O|O|O|X|X|X|X|O|X|X|O|O|O|X|O|O| |O|O|O|X|O|O|O|X|X|X|O|X|O|X|O|O|X|X|X|X|O|X|X|O|X|X|X|O|X|X|X|X|X|X|X|O|O|X|O|X| |X|O|X|O|X|X|O|O|O|X|X|X|O|O|O|O|O|O|O|X|O|X|O|X|X|X|O|X|X|O|O|X|X|X|O|X|O|O|X|O| |O|X|O|X|X|O|X|X|X|X|X|X|O|O|X|O|O|X|X|X|O|X|X|X|O|O|X|O|X|O|X|O|O|O|O|O|X|O|X|O| |O|X|X|X|O|X|O|X|X|O|X|O|O|O|O|X|X|X|O|X|X|O|X|O|O|X|O|X|O|X|O|O|O|O|O|X|O|O|O|X| |O|X|X|X|O|X|X|X|O|O|X|O|O|X|O|X|X|X|X|X|O|O|X|O|X|O|O|O|X|X|O|O|X|X|O|O|X|O|X|X| |X|X|O|O|O|O|X|X|X|O|O|X|X|X|O|O|X|O|X|O|X|X|X|O|X|O|X|O|X|O|O|O|O|O|X|X|O|O|X|O| |O|O|O|X|X|X|X|O|O|O|O|O|O|O|X|O|X|O|X|O|O|X|X|X|X|O|X|O|X|X|X|X|O|X|X|O|O|X|O|X| |O|X|X|O|O|X|O|O|X|X|O|X|O|O|O|O|O|O|X|O|X|X|X|X|X|O|O|X|X|X|X|X|X|O|X|X|X|X|O|O| |X|O|O|O|X|X|X|O|X|X|O|O|X|X|X|O|X|O|X|O|X|X|X|X|O|O|O|O|O|O|O|X|X|O|X|O|X|O|O|O| |X|O|X|O|O|O|X|X|X|O|O|X|X|O|X|O|O|O|X|X|X|O|O|O|O|O|O|O|O|O|O|X|O|X|O|O|O|O|X|X| |O|X|O|X|O|X|X|O|X|X|O|O|O|X|O|X|O|X|O|O|O|O|X|O|O|O|O|X|X|X|O|O|O|X|X|O|X|O|X|X| |O|O|O|O|O|X|X|O|X|X|X|O|X|O|X|X|O|O|O|O|O|X|O|O|O|X|O|O|O|X|X|X|X|O|X|X|X|X|X|X| |X|O|X|O|O|X|O|O|O|X|X|O|X|O|O|O|O|O|O|X|O|X|X|X|O|O|O|X|O|O|X|O|X|X|O|X|X|X|O|X| |X|O|O|O|O|X|O|X|O|O|O|O|X|X|O|O|X|X|O|X|X|X|X|O|X|X|O|O|O|X|X|O|O|O|X|O|O|O|O|O| |X|X|X|O|O|X|O|X|O|X|X|X|O|O|O|X|X|O|X|X|O|O|X|O|O|X|O|X|X|X|O|O|O|X|O|O|O|O|X|X| |X|X|X|X|X|X|O|X|O|O|O|O|X|X|O|O|X|X|X|X|O|O|X|O|O|X|X|O|X|O|X|O|X|X|O|O|O|O|O|O| |O|X|O|O|X|X|X|X|X|X|O|O|X|X|O|X|O|X|X|X|X|O|X|X|O|O|X|O|O|X|O|O|O|O|X|X|X|X|O|O| |O|O|O|X|O|O|X|O|O|X|X|X|X|X|X|X|X|X|O|O|O|X|X|O|O|O|X|O|X|O|O|X|O|X|O|X|O|X|O|X| |X|X|O|O|X|X|X|O|X|O|X|O|O|X|X|O|O|X|X|O|O|O|O|O|X|X|X|O|O|X|X|X|O|X|O|X|O|X|X|X| |O|X|O|O|O|X|X|X|X|O|X|X|X|O|O|X|O|X|X|O|X|X|O|O|X|O|X|X|O|O|X|X|O|O|O|O|O|X|O|O| |X|O|X|X|X|O|O|X|X|X|X|O|O|X|O|O|X|X|O|O|O|O|X|O|X|X|O|O|X|O|X|O|O|O|X|X|O|X|O|X| |O|X|X|O|X|O|O|X|X|O|O|O|O|O|X|X|O|O|O|X|O|X|O|O|O|X|X|O|X|O|X|X|O|X|X|O|O|O|X|X| |O|X|O|O|X|X|X|O|X|O|O|O|X|O|O|X|X|X|X|O|X|X|O|O|O|X|O|O|O|X|X|O|O|O|X|O|O|O|X|O| |O|O|X|X|O|O|O|O|X|O|O|X|X|X|X|X|X|O|X|O|O|X|X|X|X|X|X|O|X|X|X|X|O|O|X|X|O|O|X|X| |O|O|O|X|X|X|O|O|O|X|O|X|O|X|O|O|O|X|X|X|O|O|O|X|O|O|O|X|X|O|X|O|O|X|O|O|O|O|O|X| |O|O|X|O|O|X|O|O|O|O|X|X|O|O|X|O|O|O|X|O|X|O|O|X|O|X|X|O|X|X|O|O|X|X|X|X|O|O|O|O| |X|X|X|O|O|X|O|O|X|O|X|X|X|O|X|O|O|X|O|O|X|X|O|O|X|O|O|O|X|O|X|X|O|O|O|O|O|O|X|O| |O|O|X|X|O|O|X|X|X|O|O|X|O|X|X|O|O|O|X|O|X|O|O|X|X|X|O|X|X|O|O|O|O|O|X|O|O|O|X|O| |O|O|O|O|O|X|O|O|O|O|X|X|O|X|O|O|X|X|X|O|O|O|O|O|X|X|O|O|X|O|O|O|X|X|O|X|O|O|X|X| |X|O|O|O|X|O|O|X|O|O|O|O|X|O|O|X|O|X|X|X|X|O|O|X|O|X|O|O|X|X|O|O|O|X|O|X|X|X|X|X| |O|O|X|O|X|O|X|X|O|X|X|X|O|X|X|X|O|X|O|O|O|O|X|O|X|O|O|X|X|X|X|O|O|O|O|X|O|X|X|X| |O|O|X|X|X|O|O|X|O|O|X|X|O|O|O|X|O|X|X|X|X|O|X|X|X|X|X|X|O|X|X|X|X|X|O|X|O|O|X|X| |X|X|X|O|X|X|O|X|O|O|X|X|X|O|X|O|O|O|O|O|O|O|X|O|O|O|X|X|X|X|X|X|O|O|O|X|X|X|X|X| |O|X|O|O|X|O|X|X|X|X|O|X|X|X|X|X|X|X|O|O|O|O|X|O|O|X|X|O|O|O|X|X|X|O|X|O|X|O|O|O| |X|O|X|O|X|O|O|X|X|X|O|O|X|O|O|O|O|X|O|O|X|O|O|O|X|X|O|X|X|X|X|O|X|O|X|O|X|X|O|O| |X|O|X|O|O|O|O|X|O|X|O|O|O|X|X|O|O|X|O|O|O|X|O|X|X|X|X|O|X|O|O|O|O|O|X|O|O|O|X|X| |X|O|O|O|O|X|X|O|O|O|X|X|X|O|X|X|O|X|O|X|X|X|O|X|X|X|O|O|X|O|X|X|X|O|X|X|X|X|O|X| |X|O|O|O|O|O|X|O|O|X|X|O|O|O|O|X|X|O|X|X|O|X|X|X|X|X|X|X|O|O|O|X|X|X|O|O|O|O|O|X| |X|O|O|X|O|O|X|X|O|X|X|X|X|O|X|X|X|O|O|X|X|O|O|X|O|O|X|X|X|X|O|X|O|X|O|O|O|X|X|O| |X|X|X|X|O|X|O|O|O|X|O|X|O|O|X|O|O|O|X|X|X|O|X|X|O|O|O|X|X|X|X|O|X|X|O|O|O|X|O|O| |O|O|O|X|O|O|O|X|X|X|O|X|O|X|O|O|X|X|X|X|O|X|X|O|X|X|X|O|X|X|X|X|X|X|X|O|O|X|O|X| |X|O|X|O|X|X|O|O|O|X|X|X|O|O|O|O|O|O|O|X|O|X|O|X|X|X|O|X|X|O|O|X|X|X|O|X|O|O|X|O| |O|X|O|X|X|O|X|X|X|X|X|X|O|O|X|O|O|X|X|X|O|X|X|X|O|O|X|O|X|O|X|O|O|O|O|O|X|O|X|O| |O|X|X|X|O|X|O|X|X|O|X|O|O|O|O|X|X|X|O|X|X|O|X|O|O|X|O|X|O|X|O|O|O|O|O|X|O|O|O|X| |O|X|X|X|O|X|X|X|O|O|X|O|O|X|O|X|X|X|X|X|O|O|X|O|X|O|O|O|X|X|O|O|X|X|O|O|X|O|X|X| |X|X|O|O|O|O|X|X|X|O|O|X|X|X|O|O|X|O|X|O|X|X|X|O|X|O|X|O|X|O|O|O|O|O|X|X|O|O|X|O| |O|O|O|X|X|X|X|O|O|O|O|O|O|O|X|O|X|O|X|O|O|X|X|X|X|O|X|O|X|X|X|X|O|X|X|O|O|X|O|X| |O|X|X|O|O|X|O|O|X|X|O|X|O|O|O|O|O|O|X|O|X|X|X|X|X|O|O|X|X|X|X|X|X|O|X|X|X|X|O|O| |X|O|O|O|X|X|X|O|X|X|O|O|X|X|X|O|X|O|X|O|X|X|X|X|O|O|O|O|O|O|O|X|X|O|X|O|X|O|O|O| |X|O|X|O|O|O|X|X|X|O|O|X|X|O|X|O|O|O|X|X|X|O|O|O|O|O|O|O|O|O|O|X|O|X|O|O|O|O|X|X| |O|X|O|X|O|X|X|O|X|X|O|O|O|X|O|X|O|X|O|O|O|O|X|O|O|O|O|X|X|X|O|O|O|X|X|O|X|O|X|X| |O|O|O|O|O|X|X|O|X|X|X|O|X|O|X|X|O|O|O|O|O|X|O|O|O|X|O|O|O|X|X|X|X|O|X|X|X|X|X|X| |X|O|X|O|O|X|O|O|O|X|X|O|X|O|O|O|O|O|O|X|O|X|X|X|O|O|O|X|O|O|X|O|X|X|O|X|X|X|O|X| |X|O|O|O|O|X|O|X|O|O|O|O|X|X|O|O|X|X|O|X|X|X|X|O|X|X|O|O|O|X|X|O|O|O|X|O|O|O|O|O| |X|X|X|O|O|X|O|X|O|X|X|X|O|O|O|X|X|O|X|X|O|O|X|O|O|X|O|X|X|X|O|O|O|X|O|O|O|O|X|X| |X|X|X|X|X|X|O|X|O|O|O|O|X|X|O|O|X|X|X|X|O|O|X|O|O|X|X|O|X|O|X|O|X|X|O|O|O|O|O|O| |O|X|O|O|X|X|X|X|X|X|O|O|X|X|O|X|O|X|X|X|X|O|X|X|O|O|X|O|O|X|O|O|O|O|X|X|X|X|O|O| |O|O|O|X|O|O|X|O|O|X|X|X|X|X|X|X|X|X|O|O|O|X|X|O|O|O|X|O|X|O|O|X|O|X|O|X|O|X|O|X| |X|X|O|O|X|X|X|O|X|O|X|O|O|X|X|O|O|X|X|O|O|O|O|O|X|X|X|O|O|X|X|X|O|X|O|X|O|X|X|X| |O|X|O|O|O|X|X|X|X|O|X|X|X|O|O|X|O|X|X|O|X|X|O|O|X|O|X|X|O|O|X|X|O|O|O|O|O|X|O|O| |X|O|X|X|X|O|O|X|X|X|X|O|O|X|O|O|X|X|O|O|O|O|X|O|X|X|O|O|X|O|X|O|O|O|X|X|O|X|O|X| |O|X|X|O|X|O|O|X|X|O|O|O|O|O|X|X|O|O|O|X|O|X|O|O|O|X|X|O|X|O|X|X|O|X|X|O|O|O|X|X|
Instead of indirectly obtaining the Ising model time evolution as a Markov Chain over a model, we can also just directly write the kernel which moves from one state of a grid to the next, stochastically. We express the chain as a stream (a Producer
) and display that.
The one subtlety is that we need a function Store (m a) -> m (Store a)
, i.e. a Traversable
instance for Store
, so that we can expand local stochasticity to global stochasticity.
instance Foldable (Store g)
instance (Traversable g, Representable g, Functor g) => Traversable (Store g) where
sequenceA g = fmap (uncurry store . first index) (distributed g) where
distributed :: (Representable g, Traversable g, Applicative m) => Store g (m a) -> m (g a, Rep g)
distributed g = grab $
first (sequenceA . tabulate) $
runStore g
grab (ma, b) = (,b) <$> ma
step :: MonadDistribution m => Grid Bool -> m (Grid Bool)
step = sequence . extend rule
rule :: MonadDistribution m => Grid Bool -> m Bool
rule = experiment (uniformD . neighbours)
where
neighbours s = addCoords s <$> neighbourCoords
addCoords (x, y) (x', y') = (x + x', y + y')
neighbourCoords = [(x, y) | x <- [-1, 0, 1], y <- [-1, 0, 1], (x, y) /= (0, 0)]
steps :: MonadDistribution m => P.Producer (Grid Bool) m ()
steps = P.unfoldr
(fmap (Right . (\y -> (y,y))) . step)
(mkGrid [(m,n) | m <- [0..10], n <- [0..20]])
sampler $ P.runEffect (steps >-> P.drop 50 >-> P.mapM (liftIO . putStrLn . display) >-> P.take 2 >-> P.drain)
|O|O|O|O|O|O|X|X|O|X|X|X|O|O|X|O|X|O|O|O|O|O|O|O|O|O|X|O|X|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|X|O|X|O|X|X|O|X|X|O|O|O|O|O|O|O|X|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|X|O|X|X|O|X|X|O|X|X|O|O|O|X|O|O|X|O|X|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|X|O|O|X|O|X|X|O|O|X|O|O|O|O|X|O|X|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|X|O|X|X|X|O|X|O|O|O|O|X|O|O|O|O|O|O|X|X|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|X|O|X|O|X|O|O|O|X|X|O|X|O|O|O|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |X|O|O|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|X|X|O|X|X|O|O|O|O|X|X|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|X|O|X|O|X|O|O|O|X|O|X|O|O|O|X|O|O|O|O|O|O|O|O|O|O|X|X| |O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|O| |O|O|O|O|O|O|O|O|X|X|O|O|O|O|O|O|X|O|O|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|X|O|O|O| |X|O|O|O|X|O|O|X|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|O|O|O|O|O| |X|X|O|O|X|O|O|O|O|X|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X| |O|O|X|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|X|O|X|X| |X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|O|O|O|X|O|O|O|X|X|X|X| |O|O|O|O|O|O|X|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|O|X|X|O|O|O|O|O|X|O|O|O| |X|O|O|X|X|X|O|X|O|O|X|O|O|X|O|O|X|O|X|X|O|O|O|O|O|O|O|O|O|O|O|X|O|O|X|O|O|O|X|X| |X|O|X|O|X|O|O|X|O|X|O|O|O|O|O|O|O|X|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|O| |O|O|O|O|O|O|O|O|X|O|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|O|X|O|O|O|O|X| |X|O|O|O|X|X|O|X|X|O|O|O|O|O|O|X|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|X|O|O|O|O|O|O|O| |O|O|O|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|X|O|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|O|O|O|O|O|O|O|X|O|X|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|X|O|O|O|O|O|O|O|O|O|O|X|X|O|O|O|X|O|O|O|O|X|O|O|O|O|O|O|X|O|O|O|O|O|O| |O|O|O|X|O|O|O|X|O|O|O|O|O|O|O|O|O|X|X|O|O|O|O|O|O|O|O|O|X|O|O|O|O|X|X|O|X|O|O|O| |O|O|O|O|O|O|O|O|O|O|X|O|X|O|O|O|X|X|X|X|O|X|O|O|X|O|O|O|O|O|X|O|X|O|X|O|O|O|O|O| |O|O|O|O|O|O|O|O|X|O|X|X|X|O|O|X|O|X|X|X|O|X|O|O|O|O|O|X|O|O|X|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|X|X|O|X|X|O|X|X|O|O|O|X|O|O|O|O|X|O|O|O|O|O|X|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|X|X|X|X|O|X|O|O|O|O|O|O|O|O|O|X|O|O|O|O|X|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|X|O|X|O|O|X|O|X|O|O|O|O|O|O|O|O|X|O|X|O|O|X|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|X|O|X|X|X|O|X|O|O|O|O|O|O|O|X|X|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|X|X|O|X|X|X|X|O|O|O|O|O|O|O|O|O|O|O|O|X|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|X|O|O|X|O|X|O|X|X|X|X|O|O|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|X|O|O|O|O|O|X|O|X|O|O|X|O|O|O|O|X|O|O|X|O|X|O|O|O|X|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|X|X|O|O|X|O|O|X|O|O|X|O|O|O|O|O|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|X|O|O|O|O|O|O|O|O|O|X|X|O|O|O|X|X|O|O|O|O|X|X|O|O|O|O|O|O|O|O|X|O| |X|O|O|O|O|O|O|O|O|X|O|O|X|O|O|O|X|O|O|O|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X| |O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|X|O|O|X|O|O|O|X|X|O|O|O|O|O|O|O|O|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|X|X|X| |O|O|O|X|O|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|O|O|X|X|O| |X|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|O|X| |O|O|O|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|O|O|O|O|O|X|X|O|O|O|X| |O|X|O|O|O|O|X|O|X|O|O|X|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|X|X|O|O|O|O|O|X|X|X|X|X| |O|O|X|X|O|O|X|X|X|O|O|O|O|O|O|O|O|O|X|O|X|O|O|O|O|O|O|O|O|X|O|O|O|X|O|O|X|X|X|O| |O|O|O|O|X|O|X|O|O|O|O|O|O|X|X|O|O|O|X|X|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|O|O|O|O| |O|X|O|X|O|X|X|O|X|O|O|O|O|O|X|O|O|O|X|O|X|O|O|O|O|O|O|O|O|O|O|O|O|X|O|O|O|X|O|X| |X|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|O|X|O|O|X|O| |X|X|X|O|O|X|X|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O| |O|X|O|O|O|O|X|X|X|O|O|O|O|O|O|O|X|O|O|O|X|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O| |O|O|O|O|X|O|X|O|O|O|O|O|O|O|O|O|O|O|X|X|O|O|O|O|O|O|X|O|O|O|O|O|O|O|O|X|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|O|X|X|O|O|X|X|O|X|O|O|O|X|O|O|O|O|O|O|O|O|O|X|X|O|O|O|X|O|O| |O|O|X|O|O|O|O|O|O|X|O|X|X|O|O|X|X|O|X|O|O|O|O|X|O|O|X|O|O|X|X|O|O|X|O|O|O|O|O|O| |O|O|O|O|O|O|O|O|O|O|X|X|X|X|X|O|X|O|X|X|O|X|X|O|O|O|O|O|O|O|O|O|O|O|X|O|O|O|O|O| |O|O|O|O|O|O|O|X|O|O|X|O|X|X|O|O|O|O|O|X|X|O|O|O|O|X|X|O|O|O|O|O|O|O|O|O|O|O|O|O|
import IHaskell.Display.Widgets.Interactive
import IHaskell.Display.Widgets
mkPlay
<interactive>:1:1: error: Could not find module ‘IHaskell.Display.Widgets.Interactive’ Use -v (or `:set -v` in ghci) to see a list of the files searched for.