Haskell

From Wikipedia:

Haskell is a general-purpose, statically typed, purely functional programming language with type inference and lazy evaluation. Developed to be suitable for teaching, research and industrial application, Haskell has pioneered a number of advanced programming language features such as type classes, which enable type-safe operator overloading. Haskell's main implementation is the Glasgow Haskell Compiler (GHC). It is named after logician Haskell Curry.

Installation

Note: There are several choices for Haskell installation, one is supported by Arch Linux, while others are officially supported by Haskell for any Linux distributions.

Native installation

Haskell generates machine code that can be run natively on Linux. There is nothing special required to run a binary (already compiled) software, like xmonad or pandoc. On the other side, building AUR packages or developing software require a compiler and build tools to be installed.

To install the latest version of Haskell, install the following packages:

  1. ghc — A Haskell compiler. There are several implementations available, but the one used most (which is now de facto the reference) is the GHC (Glasgow Haskell Compiler).
  2. cabal-install or stack — Build tools that rely on GHC to compile Haskell sources. Cabal is the classic build tool focused on dependency resolution and source packages from Hackage (Haskell community's central package archive of open source software). Stack is another build tool focused on curated snapshots and source packages from Stackage (a stable subset of Hackage that provides curated sets (snapshots) of packages known to work well with each other).
Tip: Both Cabal and Stack are stable and mature build tools. Many Haskell developers use Cabal, while many others prefer Stack. If you are not sure which tool to choose, try to install both and see which one works best for you.

Configuration

Since version 8.0.2-1, the Arch ghc package and all haskell-* packages in community provide only dynamically linked libraries. Therefore, to link successfully one must configure GHC, Cabal and Stack for dynamic linking, as the default is to use static linking.

Using dynamic linking typically results in faster builds and smaller disk and RAM usage (by sharing pages between multiple running Haskell programs), and will free you from troubleshooting cross-GHC mixing errors. But it has its own disadvantage: all tools you install from source will break on every update of ghc, ghc-libs or haskell-* packages since libraries compiled with GHC do not provide a stable ABI. When running such broken binary, you will see the usual message . To fix this, just rebuild and reinstall the broken tool in order to relink it to newer libraries.

On the other hand, static linking is generally easier to maintain and does not force you to rebuild all tools from source after every update of their dependencies. For these reasons, static linking is often the preferred option for local development outside of the package system. If you prefer static linking, see #Static linking or #Alternate installations for details.

Invoking GHC directly

In order to link successfully one must pass the flag to GHC. You can try it with the following file:

Compile and run it with:

$ ghc -dynamic Main.hs
$ ./Main
Hello, World

Configuring Cabal for dynamic linking

First, run the following command to download the latest list of packages from Hackage and create global configuration file (or the file $CABAL_CONFIG points to):

$ cabal update

To configure Cabal for dynamic linking, uncomment and edit the following options in :

  • suppresses the creation of static libraries (if your project contains a library).
  • enables the creation of shared libraries (if your project contains a library).
  • causes dynamic linking to be used for executables (if your project contains executables).
  • adds the flag to every invocation of GHC (e.g. if a package has a non-trivial ).

Configuring Stack for dynamic linking

You can use stack setup command to initialize Stack and create global configuration file . By default Stack will automatically download its own version of GHC to an isolated location upon first invocation. To force Stack to use system GHC installation instead, run stack setup with --system-ghc and flags:

$ stack setup --system-ghc --resolver resolver

Note that you need to specify a resolver which is compatible with your system GHC. Otherwise Stack will happily ignore --system-ghc flag and download its own copy of GHC. You can determine the version of system GHC using command:

Then visit Stackage website and pick a suitable Long Term Support (LTS) or nightly snapshot matching your system GHC version. Use the selected snapshot for flag on the command line, e.g. or .

Stackage typically lags behind new GHC releases. It may happen that no Stackage snapshot for your system GHC has yet been released. In this case you might want to choose a snapshot for some earlier minor version of GHC or temporarily downgrade your Haskell installation and wait until support for newer GHC releases finally lands on Stackage.

To configure Stack for dynamic linking, add the following snippet to :

Package management

Most of Haskell libraries and executables are distributed in units of source packages available from Hackage and Stackage.

As is common in other compiled languages, a number of popular Haskell packages are available from official Arch repositories in pre-built form. Some additional packages can be installed from AUR.

Although it is recommended to use pacman to install GHC, libraries and tools — at some point you may want to install Haskell packages directly from Hackage/Stackage or compile your own (or somebody else's) packages from source. You will need Cabal or Stack for doing that.

The following table summarizes the advantages and disadvantages of different package management styles.

Method Pros Cons
Official repositoriesProvided by Arch Linux developers, consistent versions of packages, already compiledNot all packages available, only dynamic libraries available
CabalAll packages available, root not requiredInstalled in home directory, failures in dependency resolution, difficult to remove specific packages
StackAll packages available (favors Stackage), root not requiredInstalled in home directory, versions are pinned to snapshot, difficult to remove specific packages
AURAdditional packages availableRisk of unmaintained or orphaned packages, incompatible versions of packages possible

Cabal

Cabal is "the original" build system for Haskell. Most of libraries and tools you can find on Hackage can be installed via Cabal.

Installing packages

To run user-wide executables installed by Cabal, must be added to the $PATH environment variable.

PATH="$HOME/.cabal/bin:$PATH"

Run the following command to install a Hackage package and all of its dependencies in a single step:

$ cabal install --ghc-options=-dynamic package

You can also build and install a Haskell package from source. To do this, run the following command from the package directory:

$ cabal install --ghc-options=-dynamic

Each Cabal package should specify a list of its dependencies and their version constraints in the .cabal file according to the Package Versioning Policy (PVP). During the package installation, Cabal tries to find a set of dependencies that satisfies all the constraints. This process is called dependency resolution.

There are reasons why Stack exists; Cabal is known to generate a lot of friction with beginners. Most of the time dependency resolution works well but sometimes it fails. In this case you will need to figure out the cause of the problem and give Cabal some hints about how to resolve offending dependencies. For example, sometimes it is necessary to say to allow Cabal to ignore package's PVP-dictated upper bounds on dependency versions, effectively installing package with newer dependencies than the package author has permitted. It gets hairier for less-well maintained packages; for another example, see this thread about installing Idris (another programming language, written in Haskell), where one had to use both and command-line flags to get a successful compile.

Removing packages

There is no easy way to do it. Cabal does not have support for this functionality but there are external tools like cabal-store-gc.

To reinstall the entire user-wide Haskell package system, remove and and start from scratch. This is often necessary when GHC is upgraded.

For more precision, it is possible to use or /ghc-pkg expose package directly on the user package database — this makes GHC "forget" about an installed package (or pretend it is not there). However neither of these removes any files.

Stack

Stack is another tool to manage Haskell packages. It has slightly different goals than Cabal, with a slightly different philosophy. It uses Cabal library under the hood and integrates with Hackage — but maintains its own repositories of packages (snapshots) on Stackage with the promise that snapshots are curated and include packages which work well together.

Installing packages

In its default configuration, Stack installs compiled executables to . Add this directory to the $PATH environment variable in your shell configuration file, for instance for bash or for :

export PATH="$HOME/.local/bin:$PATH"

Run the following command to download, build and install a Stackage package:

stack install package

You can also build and install a Haskell package from source by running the following command from the package directory:

stack install --resolver resolver

Note that you should specify the same resolver as one used for stack setup command.

Removing packages

Stack does not support the "uninstall" operation.

If you want to reinstall the entire user-wide Haskell package system, remove directory and start from scratch. This is often necessary when GHC is upgraded.

Development tools

haskell-language-server

haskell-language-server is a Language Server Protocol (LSP) implementation for Haskell. It provides IDE-like features such as code completion, "goto definition", documentation on hover, linting, formatting or refactoring for any editor integrating with the LSP.

If you are using dynamically linked Haskell packages from pacman, install . Otherwise, if you prefer static linking, install . This package contains statically linked binaries for each supported version of GHC. Alternatively, haskell-language-server can be installed via ghcup or by the Haskell extension for Visual Studio Code.

haskell-language-server will attempt to automatically determine the build configuration when you open your project. If automatic detection fails, you might want to configure it manually using a file in the project root directory.

ghcid

ghcid is a GHCi-based tool for Haskell development that provides simple and robust way to display compiler errors and warnings on every source code change. It can be installed via ghcidAUR package.

hoogle

hoogle allows you to search the Haskell libraries by either function name, or by approximate type signature. It can be installed via package.

An online version of hoogle is available at https://hoogle.haskell.org.

hlint

hlint suggests possible improvements to Haskell code such as using alternative functions, simplifying code and spotting redundancies. It is available through package.

stan

stan is a Haskell static analyzer, complementary to hlint. It is in the beta phase as of June 2021.

weeder

weeder is an application to perform whole-program dead-code analysis.

Formatters

  • hindent Extensible Haskell pretty printer.
https://github.com/mihaimaruseac/hindent || hindent

Visual Studio Code

Visual Studio Code has a Haskell extension powered by haskell-language-server. If you do not have haskell-language-server installed, the Haskell extension will automatically download and install statically linked Linux binaries for you.

IntelliJ IDEA

IntelliJ IDEA support for Haskell is provided by the Haskell plugin. It works with any edition of IntelliJ IDEA including .

You will need to install Stack in order to create a new project or import an existing one into IntelliJ IDEA. As of June 2021 Cabal-only projects are not supported.

Vim

Basic syntax highlighting and indentation for Vim can be obtained via the haskell-vim plugin. For better IDE-like experience use one of LSP client plugins (e.g. coc.nvim, ALE, LanguageClient-neovim) together with haskell-language-server.

Emacs

Basic Emacs support for Haskell is provided by the official haskell-mode. For more advanced features, also use lsp-haskell with haskell-language-server.

Alternate installations

There are two officially recommended methods of installing Haskell on any generic Linux distribution: ghcup and Stack. Both methods install statically linked GHC, tools and libraries in your home directory.

The advantage of using ghcup or Stack instead of Haskell packages from the official repositories is the ability to install and manage multiple versions of GHC side by side. Cabal and Stack installed this way typically work right out of the box without any additional configuration, which might be easier for beginners.

A completely different way of installing Haskell is Nix package manager. Nix has a steeper learning curve but offers greater flexibility in managing both Haskell and non-Haskell packages in a reliable and reproducible fashion.

ghcup

ghcup is a command line tool that allows to easily install multiple versions of GHC and switch between them. It is similar in scope to rustup, pyenv and jenv.

Install ghcup-hs-binAUR package. Alternatively, you may follow official installation instructions or manually download ghcup binary and place it somewhere into your $PATH.

By default, ghcup will install GHC executables into . You need to add this directory to the $PATH environment variable in your shell configuration file, for instance for bash or for . If you want to run executables installed by Cabal, add to $PATH as well:

export PATH="$HOME/.cabal/bin:$HOME/.ghcup/bin:$PATH"

ghcup provides a convenient TUI which supports most of its functionality:

$ ghcup tui

Alternatively, you can use the following CLI commands:

List available versions of GHC and Cabal:

$ ghcup list

Install the recommended version of GHC:

$ ghcup install ghc

You can also install a specific version of GHC, for example:

$ ghcup install ghc 8.10.2

The commands above do not automatically make GHC available on the $PATH. You need to select which GHC version to use by default:

$ ghcup set ghc 8.10.2

Install the recommended version of Cabal:

$ ghcup install cabal

You can now use Cabal to build and install statically linked Haskell executables without any special configuration or command line flags:

To start a new Cabal project:

To install haskell-language-server, use the following command:

$ ghcup install hls

For more information, refer to official ghcup and Cabal documentation.

Stack

Install package. Alternatively, you may follow official installation instructions or manually download Stack binary and place it somewhere into your $PATH.

If you want to run executables installed by Stack, add directory to the $PATH environment variable in your shell configuration file, for instance for bash or for :

export PATH="$HOME/.local/bin:$PATH"

Run stack setup to automatically install GHC from the latest Stackage LTS snapshot:

$ stack setup

You can now use Stack to build and install statically linked Haskell packages without any special configuration or command line flags:

$ stack install package

For more information, refer to official Stack documentation.

Tips and tricks

Static linking

Note: In the context of this article, static linking does not mean generating completely static ELF binaries. Only Haskell code will be linked statically into a single ELF binary, which may be dynamically linked to other system libraries such as glibc.

To use static linking, one must, at minimum, install the static boot libraries through the package. This would allow you to build projects that depend exclusively on the boot libraries as well as on any other libraries that are not installed through the packages from the official repositories.

Unfortunately, if your project depends on any of dynamically linked packages that you have installed, Cabal does not take the absence of static libraries into account during dependency resolution. As a result, it will try to use the existing package and then fail with linker errors when it discovers the static libraries are missing:

Could not find module ‘SomePackage.SomeModule’
There are files missing in the ‘somepackage-0.1.0.0’ package,
try running 'ghc-pkg check'.
Use -v (or `:set -v` in ghci) to see a list of the files searched for.

Unlike ghc-static, there are no "" packages available for linkage. There are other ways to work around this issue though, as described in each of the sections below.

Static global package database

A direct approach is offered by the official package, which exposes an alternative "static" global package database at . The static database is limited to only the statically linkable boot packages, therefore if Cabal is reconfigured to use the static database instead of the default database, it would behave as though the dynamic-only packages do not exist.

The precise path of the static database could be determined at build time using a command such as:

Here is how to enable the static database for use:

  • When building packages with Cabal, one can pass the following flag to limit the selection of global packages to only the boot packages:
$ cabal configure --ghc-pkg-option="--global-package-db=$(ghc --print-global-package-db | sed 's/\(package\.conf\.d\)$/static-\1/')"
  • When building directly using GHC rather than Cabal, one can pass the following flags to override the global package database:
$ ghc -clear-package-db -package-db "$(ghc --print-global-package-db | sed 's/\(package\.conf\.d\)$/static-\1/')" -user-package-db ...

ghc-pristine

Install package, which wraps over an existing GHC installation to create a separate GHC distribution in , with a package database that contains only boot libraries. This effectively creates a semi-isolated environment without dynamically linked packages, but still makes use of the GHC compiler from the official repositories. Then, to build software with static linking, one simply needs to invoke the wrapped compiler . For Cabal, this amounts to the following configuration in :

~/.cabal/config
with-compiler: /usr/share/ghc-pristine/bin/ghc

You can also specify the path to the compiler on a per-project basis by running the following command from the project directory:

$ cabal configure --with-compiler=/usr/share/ghc-pristine/bin/ghc

cabal-static

Another way to gain back static linking on Arch is to install package. Unlike the official cabal-install, this one does not pull dynamically linked dependencies from the official repositories and avoids mixing static and shared Haskell libraries installed on the same system. Then you can use Cabal as usual with the following limitation: you have to make sure that the only other Haskell packages you have installed are ghc, ghc-libs and (not cabal-install, stack and none of the packages available in the official repositories).

stack-static

Install package. Similarly to method, make sure that the only other Haskell packages you have installed from the official repositories are ghc, ghc-libs and . Then setup Stack to use system GHC as explained in #Configuring Stack for dynamic linking:

$ stack setup --system-ghc --resolver resolver

To make these options permanent, paste the following snippet to :

This configuration will allow you to build statically linked packages as you would normally do, but using system GHC installation instead of GHC provided by Stack.

hpack-static-bin

provides a statically linked (meaning no  dependencies) alternative to haskell-hpack. It is precompiled, so no make dependencies are needed.

ghcup

ghcup is a tool that can install GHC locally, entirely outside the system package manager. Additionally, it supports multiple versions of GHC side by side. Using the GHC provided by this tool will completely avoid the difficulties associated with static linking since the system GHC is not used at all. It also naturally avoids breakages in locally built libraries caused by upgrades of the system GHC and its boot libraries.

gollark: The UK is pretty horrible for that sort of thing.
gollark: I mean, for actual programmers, HTML is a simple thing to learn which they probably shouldn't list, CSS is too, PHP is horrible, JS is not great, and C# is eeeeh.
gollark: Also, if you do anything other than the course, enjoy people probably calling you a hacker!
gollark: ?
gollark: Don't they already get stupid amounts of money.

See also

This article is issued from Archlinux. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.