first commit

This commit is contained in:
David Alst 2024-06-16 21:29:40 +02:00
commit 52e52ba036
11 changed files with 428 additions and 0 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

34
.devcontainer/.ghci Normal file
View file

@ -0,0 +1,34 @@
:set prompt "\ESC[94m\STX \ESC[m\STX"
:set prompt-cont "\ESC[1;32mλ| \ESC[m"
:set +t
:set +m
:set +s
:set editor emacs
:set -Wall
:set -ferror-spans
:set -freverse-errors
:set -fprint-expanded-synonyms
:set -fprint-explicit-foralls
:set -fprint-explicit-kinds
:set -ignore-package pretty-simple -package pretty-simple
-- :set -fobject-code
:seti -XFlexibleContexts
:seti -XFlexibleInstances
:seti -XOverloadedStrings
:seti -XGADTSyntax
:seti -XGeneralizedNewtypeDeriving
:seti -XInstanceSigs
:seti -XLambdaCase
:seti -XPartialTypeSignatures
:seti -XScopedTypeVariables
:seti -XPolyKinds
:seti -XDataKinds
:seti -XTypeApplications
:seti -XTypeApplications
:def hlint const . return $ ":! hlint \"src\""
:def hoogle \s -> return $ ":! hoogle --count=15 \"" ++ s ++ "\""
:def package \ m -> return $ ":! ghc-pkg --simple-output find-module " ++ m

105
.devcontainer/Dockerfile Normal file
View file

@ -0,0 +1,105 @@
FROM debian:bookworm-slim as base
ENV LANG C.UTF-8
ARG GHC_VERSION=9.6.3
ARG STACK_VERSION=recommended
ARG STACK_RESOLVER=lts-22.6
ARG CABAL_VERSION=recommended
ARG HLS_VERSION=recommended
ARG LLVM_VERSION=17
ENV USERNAME=vscode \
USER_UID=1000 \
USER_GID=1000 \
DEBIAN_FRONTEND=noninteractive \
GHC_VERSION=${GHC_VERSION} \
STACK_VERSION=${STACK_VERSION} \
STACK_RESOLVER=${STACK_RESOLVER} \
CABAL_VERSION=${CABAL_VERSION} \
HLS_VERSION=${HLS_VERSION} \
LLVM_VERSION=${LLVM_VERSION}
RUN ulimit -n 8192
RUN VERSION_CODENAME=$(grep VERSION_CODENAME /etc/os-release | cut -d'=' -f2) && \
apt-get update && \
apt-get install -y --no-install-recommends software-properties-common wget && \
# I don't know why, nor do I have any mental capacity to figure it out,
# but we need to add the repository twice, otherwise it doesn't work (repo isn't being added)
add-apt-repository -y -s -n "deb http://apt.llvm.org/${VERSION_CODENAME}/ llvm-toolchain-${VERSION_CODENAME}-${LLVM_VERSION} main" && \
add-apt-repository -y -s -n "deb http://apt.llvm.org/${VERSION_CODENAME}/ llvm-toolchain-${VERSION_CODENAME}-${LLVM_VERSION} main" && \
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc && \
apt-get update && \
apt-get install -y --no-install-recommends apt-utils bash build-essential ca-certificates curl gcc git gnupg libffi-dev libffi8 libgmp-dev libgmp-dev libgmp10 libicu-dev libncurses-dev libncurses5 libnuma1 libnuma-dev libtinfo5 lsb-release make procps sudo xz-utils z3 zlib1g-dev clang-$LLVM_VERSION lldb-$LLVM_VERSION lld-$LLVM_VERSION clangd-$LLVM_VERSION
RUN groupadd --gid ${USER_GID} ${USERNAME} && \
useradd -ms /bin/bash -K MAIL_DIR=/dev/null --uid ${USER_UID} --gid ${USER_GID} -m ${USERNAME} && \
echo ${USERNAME} ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/${USERNAME} && \
chmod 0440 /etc/sudoers.d/${USERNAME}
USER ${USER_UID}:${USER_GID}
WORKDIR /home/${USERNAME}
ENV PATH="/home/${USERNAME}/.local/bin:/home/${USERNAME}/.cabal/bin:/home/${USERNAME}/.ghcup/bin:$PATH"
RUN echo "export PATH=${PATH}" >> /home/${USERNAME}/.profile
ENV BOOTSTRAP_HASKELL_NONINTERACTIVE=yes \
BOOTSTRAP_HASKELL_NO_UPGRADE=yes
FROM base as tooling
RUN curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
# Set the GHC version.
RUN ghcup install ghc ${GHC_VERSION} --set
# Install cabal-iinstall
RUN ghcup install cabal ${CABAL_VERSION} --set
# Update Cabal.
RUN cabal update && cabal new-install cabal-install
# Configure cabal
RUN cabal user-config update -f && \
sed -i 's/-- ghc-options:/ghc-options: -haddock/g' ~/.cabal/config
# Install stack
RUN ghcup install stack ${STACK_VERSION} --set
# Set system-ghc, install-ghc and resolver for stack.
RUN ((stack ghc -- --version 2>/dev/null) || true) && \
# Set global defaults for stack.
stack config --system-ghc set system-ghc true --global && \
stack config --system-ghc set install-ghc false --global && \
stack config --system-ghc set resolver ${STACK_RESOLVER}
# Set global custom defaults for stack.
RUN printf "ghc-options:\n \"\$everything\": -haddock\n" >> /home/${USERNAME}/.stack/config.yaml
# Install hls
RUN ghcup install hls ${HLS_VERSION} --set
FROM tooling as packages
# Install global packages.
# Versions are pinned, since we don't want to accidentally break anything (by always installing latest).
RUN cabal install --haddock-hoogle --minimize-conflict-set \
fsnotify \
haskell-dap \
ghci-dap \
haskell-debug-adapter \
hlint \
apply-refact \
retrie \
hoogle \
ormolu
FROM packages as hoogle
# Generate hoogle db
RUN hoogle generate --download --haskell
ENV DEBIAN_FRONTEND=dialog
ENTRYPOINT ["/bin/bash"]

View file

@ -0,0 +1,51 @@
{
"name": "DevContainer for Haskell (GHC, Stack, Cabal, HIE, LSP, DAP, etc.)",
"remoteUser": "vscode",
"runArgs": [],
"build": {
"args": {
"USERNAME": "vscode",
"GHC_VERSION": "9.6.3",
"STACK_VERSION": "recommended",
"STACK_RESOLVER": "lts-22.6",
"CABAL_VERSION": "recommended",
"HLS_VERSION": "recommended",
"LLVM_VERSION": "17"
},
"context": "..",
"dockerfile": "Dockerfile"
},
"customizations": {
"vscode": {
"extensions": [
"haskell.haskell",
"phoityne.phoityne-vscode",
"eriksik2.vscode-ghci",
"jcanero.hoogle-vscode"
],
"settings": {
"files.exclude": {
"**/*.olean": true,
"**/.DS_Store": true,
"**/.git": true,
"**/.hg": true,
"**/.svn": true,
"**/CVS": true
},
"haskell.checkProject": true,
"haskell.formattingProvider": "ormolu",
"haskell.indentationRules.enabled": true,
"haskell.liquidOn": false,
"haskell.checkParents": "CheckOnSave",
"haskell.manageHLS": "GHCup",
"haskell.maxCompletions": 40,
"haskell.openDocumentationInHackage": false,
"haskell.openSourceInHackage": false,
"haskell.trace.client": "error",
"haskell.trace.server": "off",
"haskell.upgradeGHCup": true,
"hoogle-vscode.useCabalDependencies": true
}
}
}
}

50
.vscode/tasks.json vendored Normal file
View file

@ -0,0 +1,50 @@
{
// Automatically created by phoityne-vscode extension.
"version": "2.0.0",
"presentation": {
"reveal": "always",
"panel": "new"
},
"tasks": [
{
// F7
"group": {
"kind": "build",
"isDefault": true
},
"label": "haskell build",
"type": "shell",
//"command": "cabal configure && cabal build"
"command": "stack build"
},
{
// F6
"group": "build",
"type": "shell",
"label": "haskell clean & build",
//"command": "cabal clean && cabal configure && cabal build"
"command": "stack clean && stack build"
//"command": "stack clean ; stack build" // for powershell
},
{
// F8
"group": {
"kind": "test",
"isDefault": true
},
"type": "shell",
"label": "haskell test",
//"command": "cabal test"
"command": "stack test"
},
{
// F6
"isBackground": true,
"type": "shell",
"label": "haskell watch",
"command": "stack build --test --no-run-tests --file-watch"
}
]
}

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Igal Tabachnik
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

164
README.md Normal file
View file

@ -0,0 +1,164 @@
# A (highly opinionated) Docker image for Haskell development
**Note**: The way this container setup is very opinionaed, you may want to check out [an official dev containter for Haskell](https://github.com/microsoft/vscode-dev-containers/tree/main/containers/haskell).
<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->
**Table of Contents**
- [A (highly opinionated) Docker image for Haskell development](#a-highly-opinionated-docker-image-for-haskell-development)
- [Visual Studio Code: DevContainer for Haskell](#visual-studio-code-devcontainer-for-haskell)
- [What is this](#what-is-this)
- [How to use this](#how-to-use-this)
- [How does it work](#how-does-it-work)
- [What's in the box](#whats-in-the-box)
- [How to build locally](#how-to-build-locally)
<!-- markdown-toc end -->
## Visual Studio Code: DevContainer for Haskell
### What is this
This is a DevContainer <sup>[[1](https://code.visualstudio.com/docs/remote/containers)][[2](https://code.visualstudio.com/docs/remote/containers-advanced)]</sup> environment for Visual Studio Code, allowing automatically installing the Haskell compiler (GHC), Stack, Cabal, HLS (Haskell Language Server), and the necessary Visual Studio Code extensions to set up a Haskell development environment with zero additional effort.
**Note**: For debugging support, please refer to [Haskell GHCi Debugger Adapter Phoityne](https://marketplace.visualstudio.com/items?itemName=phoityne.phoityne-vscode) extension documentation.
### How to use this
Follow the [Getting Started](https://code.visualstudio.com/docs/remote/containers#_getting-started) instructions to configure your Visual Studio Code and Docker to use with DevContainers.
Place the `.devcontainer` directory in the root of your project, and the next time you load the project, Visual Studio Code will prompt to re-open the project in a container:
![image](https://user-images.githubusercontent.com/601206/73298150-7bfac580-4215-11ea-81d3-a8fabab98e30.png)
**Note**: building the container might take a few minutes until all dependencies have finished downloading and installing.
### How does it work
Visual Studio Code supports [Developing inside a Container](https://code.visualstudio.com/docs/remote/containers) - using a Docker image as a development environment. It automates the process of creating the container image, as well as installing additional required extensions into the editor.
Pressing **Reopen in Container** will perform the automated steps to launch the container, and set up the environment.
For more information and setup, read the official documentation: <https://code.visualstudio.com/docs/remote/containers> and <https://code.visualstudio.com/docs/remote/containers-advanced>
## What's in the box
[`.devcontainer/Dockerfile`](.devcontainer/Dockerfile) DevContainer Docker image.
[`debian:bullseye`](https://hub.docker.com/_/debian) as a base image.
Additional software installed:
- Glasgow Haskell Compiler (GHC) via [ghcup](https://www.haskell.org/ghcup/).
- A Haskell LSP server HLS - ([haskell-language-server](https://github.com/haskell/haskell-language-server)).
- [Stack](https://docs.haskellstack.org/en/stable/README/).
- [Cabal](https://www.haskell.org/cabal/).
- Following Debian packages: `apt-utils bash build-essential ca-certificates curl gcc git gnupg libffi-dev libffi7 libgmp-dev libgmp-dev libgmp10 libicu-dev libncurses-dev libncurses5 libnuma1 libnuma-dev libtinfo5 lsb-release make procps software-properties-common sudo wget xz-utils z3 zlib1g-dev`.
- Following Haskell packages (via [cabal](https://nixos.org/nixos/packages.html)): `haskell-dap ghci-dap haskell-debug-adapter hlint apply-refact retrie stylish-haskell hoogle ormolu liquidhaskell`.
- LLVM 12 via [LLVM Automatic installation script](https://apt.llvm.org/).
**NOTE:** *When changing GHC/HLS versions, please refer to the [GHC/HLS compatibility table](https://haskell-language-server.readthedocs.io/en/latest/supported-versions.html).*
Following VSCode extensions are installed after container is started:
- [Haskell extension](https://marketplace.visualstudio.com/items?itemName=haskell.haskell).
- [Haskell GHCi Debugger Adapter](https://marketplace.visualstudio.com/items?itemName=phoityne.phoityne-vscode).
- [Integrated Haskell Shell](https://marketplace.visualstudio.com/items?itemName=eriksik2.vscode-ghci).
- [Hoogle for VSCode](https://marketplace.visualstudio.com/items?itemName=jcanero.hoogle-vscode).
The [`devcontainer.json`](.devcontainer/devcontainer.json) has some additional configuration for VSCode, in particular, the required extensions that have to be installed, the name of the remote user (must match the one in the [`Dockerfile`](.devcontainer/Dockerfile)), and...⏎
<details>
<summary>... the following settings</summary>
```json
{
"files.exclude": {
"**/*.olean": true,
"**/.DS_Store": true,
"**/.git": true,
"**/.hg": true,
"**/.svn": true,
"**/CVS": true
},
"haskell.checkProject": true,
"haskell.formattingProvider": "ormolu",
"haskell.indentationRules.enabled": true,
"haskell.liquidOn": true,
"haskell.manageHLS": "GHCup",
"haskell.maxCompletions": 40,
"haskell.openDocumentationInHackage": false,
"haskell.openSourceInHackage": false,
"haskell.plugin.alternateNumberFormat.globalOn": true,
"haskell.plugin.callHierarchy.globalOn": true,
"haskell.plugin.changeTypeSignature.globalOn": true,
"haskell.plugin.class.globalOn": true,
"haskell.plugin.eval.config.diff": true,
"haskell.plugin.eval.config.exception": true,
"haskell.plugin.eval.globalOn": true,
"haskell.plugin.ghcide-code-actions-bindings.globalOn": true,
"haskell.plugin.ghcide-code-actions-fill-holes.globalOn": true,
"haskell.plugin.ghcide-code-actions-imports-exports.globalOn": true,
"haskell.plugin.ghcide-code-actions-type-signatures.globalOn": true,
"haskell.plugin.ghcide-completions.config.autoExtendOn": true,
"haskell.plugin.ghcide-completions.config.snippetsOn": true,
"haskell.plugin.ghcide-completions.globalOn": true,
"haskell.plugin.ghcide-hover-and-symbols.hoverOn": true,
"haskell.plugin.ghcide-hover-and-symbols.symbolsOn": true,
"haskell.plugin.ghcide-type-lenses.config.mode": "always",
"haskell.plugin.ghcide-type-lenses.globalOn": true,
"haskell.plugin.haddockComments.globalOn": true,
"haskell.plugin.hlint.codeActionsOn": true,
"haskell.plugin.hlint.config.flags": [],
"haskell.plugin.hlint.diagnosticsOn": true,
"haskell.plugin.importLens.codeActionsOn": true,
"haskell.plugin.importLens.codeLensOn": true,
"haskell.plugin.moduleName.globalOn": true,
"haskell.plugin.pragmas.codeActionsOn": true,
"haskell.plugin.pragmas.completionOn": true,
"haskell.plugin.qualifyImportedNames.globalOn": true,
"haskell.plugin.refineImports.codeActionsOn": true,
"haskell.plugin.refineImports.codeLensOn": true,
"haskell.plugin.refineImports.globalOn": true,
"haskell.plugin.rename.config.crossModule": true,
"haskell.plugin.rename.globalOn": true,
"haskell.plugin.retrie.globalOn": true,
"haskell.plugin.splice.globalOn": true,
"haskell.plugin.tactic.config.max_use_ctor_actions": 5,
"haskell.plugin.tactics.codeActionsOn": true,
"haskell.plugin.tactics.codeLensOn": true,
"haskell.plugin.tactics.config.auto_gas": 4,
"haskell.plugin.tactics.config.hole_severity": "hint",
"haskell.plugin.tactics.config.max_use_ctor_actions": 5,
"haskell.plugin.tactics.config.proofstate_styling": true,
"haskell.plugin.tactics.config.timeout_duration": 5,
"haskell.plugin.tactics.globalOn": true,
"haskell.plugin.tactics.hoverOn": true,
"haskell.trace.client": "error",
"haskell.trace.server": "off",
"haskell.upgradeGHCup": true,
"hoogle-vscode.useCabalDependencies": true
}
```
</details>
This was initially based on the [DevContainer for HIE (Haskell IDE Engine)](https://github.com/hmemcpy/haskell-hie-devcontainer) by [Igal Tabachnik](https://github.com/hmemcpy).
### How to build locally
To build the image locally, just run `docker build ./.devcontainer/ --file ./.devcontainer/Dockerfile --tag haskelldevenv:latest` in the repository root.
You can override GHC version, Cabal version, Stack resolver and HLS version by specifying `GHC_VERSION=...`, `CABAL_VERSION=...`, `STACK_RESOLVER=...` and `HLS_VERSION=...` respectively as build args.
For example:
- `docker build ./.devcontainer/ --file ./.devcontainer/Dockerfile --tag haskelldevenv:latest --build-arg GHC_VERSION=8.10.7`
- `docker build ./.devcontainer/ --file ./.devcontainer/Dockerfile --tag haskelldevenv:latest --build-arg STACK_RESOLVER=lts-18.13`
- `docker build ./.devcontainer/ --file ./.devcontainer/Dockerfile --tag haskelldevenv:latest --build-arg CABAL_VERSION=3.6.2.0`
- `docker build ./.devcontainer/ --file ./.devcontainer/Dockerfile --tag haskelldevenv:latest --build-arg HLS_VERSION=1.5.1`
- `docker build ./.devcontainer/ --file ./.devcontainer/Dockerfile --tag haskelldevenv:latest --build-arg GHC_VERSION=8.8.4 --build-arg STACK_RESOLVER=lts-18.13 --build-arg CABAL_VERSION=3.6.2.0 --build-arg HLS_VERSION=1.5.1`
To run the image, just do `docker run --rm -it haskelldevenv:latest`.
Valid values for `GHC_VERSION` can be found [here](https://www.haskell.org/ghc/download.html).

BIN
programs/hello Executable file

Binary file not shown.

BIN
programs/hello.hi Normal file

Binary file not shown.

3
programs/hello.hs Normal file
View file

@ -0,0 +1,3 @@
main = do
putStrLn "Hello, everybody!"
putStrLn ("Please look at my favorite odd numbers: " ++ show (filter odd [10..20]))

BIN
programs/hello.o Normal file

Binary file not shown.