Haskell Environment
(With IHaskell)
This notebook describes and creates the Haskell environment in Nextjournal. Check out the showcase if you want to see what the environment contains. To see how it’s built, see setup.
Showcase
Built packages:
echo "Package,Version" > /results/pkg.csvstack exec ghc-pkg -- list | grep -v -e '/' -e "^$" -e "(no packages)" | \  sort | sed 's/-\([0-9]\)/,\1/' >> /results/pkg.csvHello World
import IHaskell.Displayhtml "<strong>Works!</strong>"Diagrams
:extension NoMonomorphismRestriction FlexibleContexts TypeFamiliesimport Control.Monadimport Control.Monad.Stateimport System.Randomimport Data.Randomimport Data.Random.Distribution.Paretoimport Data.RVarimport Diagrams.Prelude hiding (normal)--import Data.Colour.Palette.BrewerSetimport qualified Diagrams.Color.XKCD as XKCDimport Data.Colour (withOpacity)randomNormal :: (Num a, Distribution Normal a) => RVar arandomNormal = normal 0 1randomPareto :: (Floating a, Distribution StdUniform a) => RVar arandomPareto = pareto 1 1randomVariable :: (Floating b, Distribution StdUniform b, Distribution Normal b)                   => RVarT Identity brandomVariable = (*) <$> randomPareto <*> randomNormalsampleNormal :: State StdGen DoublesampleNormal = sampleRVar randomNormalsampleVariable = sampleRVar randomVariableevalState sampleNormal $ mkStdGen 1evalState sampleVariable $ mkStdGen 1bubble r = circle r # lw none # fcA (blue `withOpacity` 0.2)-- RVarT Identity brandBubbles n = do    rs <- replicateM n $ normal 1 1    xs <- replicateM n $ normal 0 20    ys <- replicateM n $ normal 0 20    let points = map p2 $ zip xs ys        bubbles  = map bubble rs    return $ position (zip points bubbles)          -- (MonadRandom m, ...) m asampleBubbles n = sampleRVar $ randBubbles nwithImgHeight 500 $ diagram $ evalState (sampleBubbles 250) $ mkStdGen 1Setup
This build is a mix of several methods, with the addition of some simple management scripts to help with adding new packages. The stack development environment manager is geared towards projects, which makes it a little awkward for a more open-ended case like an IHaskell notebook environment. As has been stated many times in many forums, "Stack is not a package manager," so we have to pick up the slack.
The biggest problem is that, for some packages that require dependencies outside of the curated Stackage system, we must add specific versions from Hackage to the extra-deps section of stack.yaml.  This is easy enough with sed, but changing stack.yaml also has the effect of resetting things so that the next stack build will make many currently built packages inaccessible (their builds are still cached, but they cannot be imported).
In order to get around this and have the effect of 'adding' packages to our current setup, we need to keep a list of currently installed packages, add to that, and then rebuild the whole environment. To accomplish this:
- The global - stack.yamlis initialized to a reasonable state for IHaskell.
- The script - stack-add-deps.shis provided. Run with a list of versioned Hackage packages, and it will insert them into the- extra-depssection of- stack.yaml.
- The file - /opt/stack/build.listhas the set of packages to build.
- The file - /opt/stack/install.listhas packages with binaries to make globally available (i.e. they can be run directly in Bash).
- The script - update.shreads the two lists above, and makes the current state of the environment match what they say.
The workflow is thus:
- stack-add-deps.sh <deps>
- echo <new packages> >> /opt/stack/build.list
- echo <new global binaries> >> /opt/stack/install.list(optional)
- stack-update.sh
An example of steps 1, 2, and 4 can be seen in the first cell of the last Setup section.
Base Environment
This environment is used for compilation, and also as a base for the install. Kept minimal so that it can be rebuilt and an existing Stack/Haskell compilation carried over via tarfile, eliminating recompilation for small changes.
Install system dependencies.
apt-get -qq updateDEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends \  libmagic-dev libtinfo-dev libblas-dev liblapack-dev \  netbase graphviz libgmp-dev libicu-dev alex happyapt-get cleanrm -r /var/lib/apt/lists/*Install Jupyter extras.
pip3 install \  jupyter_nbextensions_configurator jupyter_contrib_nbextensionsdu -hsx /Stack
Install and build here generally follow instructions for IHaskell https://github.com/gibiansky/IHaskell#installation
Install the stack development tool.  The STACK_ROOT environment variable is configured in the Runtime Settings.
echo "Stack root: $STACK_ROOT"mkdir -p $STACK_ROOT/global-projectmkdir -p $STACK_ROOT/binchmod -R g+rwX $STACK_ROOTecho "local-bin-path: $STACK_ROOT/bin" > $STACK_ROOT/config.yamlcurl -qsSL https://get.haskellstack.org/ | sh -s -- -d /opt/stack/binInitialize the package index.
stack updateBarebones stack.yaml.
# Stack global project /opt/stack/global-project/stack.yaml# https://docs.haskellstack.org/en/stable/yaml_configuration/#yaml-configurationpackagesextra-deps# - extra insertion point -# Default resolverresolverlts-14.17A script to add dependencies to the extra-deps section in the global stack.yaml.
#!/bin/shfor dep in $@; do  sed -i "s/extra-deps:/extra-deps:\n- ${dep}/" \    ${STACK_ROOT}/global-project/stack.yamldoneAnd another script, to build all packages in build.list and then globally install those listed in install.list.
#!/bin/sh# Buildfor package in $(cat ${STACK_ROOT}/build.list); do  stack build ${package}done# Install global binariesfor package in $(cat ${STACK_ROOT}/install.list); do  stack install ${package}doneInitial package lists for the above script.
hpack cabal-installhpack cabal-installBase install.
cd /optstack setupchmod +x ${STACK_ROOT}/bin/stack*.shstack-update.shLink for global running.
ln -s /opt/stack/programs/x86_64-linux/ghc-8.6.5/bin/ghc \  /opt/stack/bin/Check.
du -hsx /stack --versionghc --versionSave. Locked for safety.
cd /opttar -zcf /results/haskell-stack-njinst.tar.gz stackIHaskell Build
Setup Depends
We're using a Docker building strategy similar to the one followed by https://github.com/jamesdbrock/ihaskell-notebook to avoid issue https://github.com/gibiansky/IHaskell/issues/715.
Clone and install IHaskell, and copy its resolver to global stack.yaml.
cd /optgit clone https://github.com/gibiansky/IHaskellInsert IHaskell deps and suchlike. All the IHaskell packages are listed as extra-deps rather than packages, because we never want to build anything automatically, we always want to select exactly what we build for the IHaskell notebook environment. For example, `stack ghci` tries to load every package listed in `packages`, and we don't want that behavior. Several of these packages are unbuildable at the time of this writing.
See the Dockerfile for the list of packages which are pre-built into the Docker image.
extra-deps/opt/IHaskell/opt/IHaskell/ipython-kernel/opt/IHaskell/ghc-parser/opt/IHaskell/ihaskell-display/ihaskell-aeson/opt/IHaskell/ihaskell-display/ihaskell-blaze/opt/IHaskell/ihaskell-display/ihaskell-charts/opt/IHaskell/ihaskell-display/ihaskell-diagrams/opt/IHaskell/ihaskell-display/ihaskell-gnuplot/opt/IHaskell/ihaskell-display/ihaskell-graphviz/opt/IHaskell/ihaskell-display/ihaskell-hatex/opt/IHaskell/ihaskell-display/ihaskell-juicypixels/opt/IHaskell/ihaskell-display/ihaskell-magic/opt/IHaskell/ihaskell-display/ihaskell-plot/opt/IHaskell/ihaskell-display/ihaskell-rlangqq/opt/IHaskell/ihaskell-display/ihaskell-static-canvas# - /opt/IHaskell/ihaskell-display/ihaskell-widgets# Build Vega# - /opt/hvega/hvega# - /opt/hvega/ihaskell-hvegased -i 's!extra-deps:!cat /tmp/ihaskell-edeps!e' \  /opt/stack/global-project/stack.yamlecho 'ipython-kernelihaskell ihaskell-aeson ihaskell-blaze ihaskell-gnuplot ihaskell-juicypixels ihaskell-graphviz' >> ${STACK_ROOT}/build.listecho 'ihaskell' >> ${STACK_ROOT}/install.listFinal stack.yaml:
cat ${STACK_ROOT}/global-project/stack.yamlBuild
Install IHaskell and the base setup.
cd /optstack setupchmod +x ${STACK_ROOT}/bin/stack*.shstack-update.sh# Install IHaskell.Display libraries# https://github.com/gibiansky/IHaskell/tree/master/ihaskell-display# Skip install of ihaskell-widgets, they don't work.# See https://github.com/gibiansky/IHaskell/issues/870#   stack build --fast ihaskell-widgetsihaskell install --debug --stackInstall Additional Packages
Install extra packages for graphics work.
echo 'rvar random-fu colour palette diagrams diagrams-cairo Chart Chart-cairoihaskell-charts ihaskell-diagrams' >> ${STACK_ROOT}/build.list# These are all deps for the Cairo chain:stack-add-deps.sh gtk2hs-buildtools-0.13.5.0 glib-0.13.7.0 \  cairo-0.13.6.0 pango-0.13.6.0 diagrams-cairo-1.4.1 Chart-cairo-1.9.1stack-update.shecho "Package,Version" > /results/pkg.csvstack exec ghc-pkg -- list | grep -v -e '/' -e "^$" -e "(no packages)" | \  sort | sed 's/-\([0-9]\)/,\1/' >> /results/pkg.csvCheck.
du -hsx /Tar up the whole shebang. Locked for safety.
Last compile: GHC v8.6.5, IHaskell v0.10.0.2, Dec 19th 2019.
cd /opttar -zcf /results/ihaskell-njinst.tar.gz stack IHaskellMain Environment
Untar the built Stack/Haskell/IHaskell blob.
mkdir -p /optcd /opttar -zxf NJ__REF_Install the IHaskell kernel.
ihaskell install --debug --stackCheck.
du -hsx /stack --version/opt/stack/programs/x86_64-linux/ghc-8.6.5/bin/ghc --versionjupyter kernelspec list