跳转至内容

Haskell

来自 ArchWiki
(重定向自 Stack (Haskell))

来自 Wikipedia

  • 它是一种通用、静态类型、纯函数式编程语言,具有类型推断和惰性求值;
  • 它开创了类型类,实现了类型安全的运算符重载。

安装

对于 Haskell 的安装有几种选择。一种由 Arch Linux 支持,而其他几种由 Haskell 官方支持,适用于任何 Linux 发行版。

自版本 8.0.2-1 以来,Arch 的 ghc 包和 extra 仓库中的所有 haskell-* 包仅提供动态链接库。

使用动态链接通常可以加快构建速度,并减小磁盘和内存占用(通过在多个运行的 Haskell 程序之间共享页面),而且可以避免处理跨 GHC 混合错误。因此,对于管理最终用户应用程序,推荐使用 pacman官方仓库。但它也有自己的缺点:**你从源代码安装的所有工具在每次更新 ghcghc-libshaskell-* 包时都会损坏**,因为用 GHC 编译的库不提供稳定的 ABI。运行这种损坏的二进制文件时,您会看到常见的错误消息

error while loading shared libraries: libHS...so: cannot open shared object file: No such file or directory

要解决此问题,只需重新构建并重新安装损坏的工具,以便将其重新链接到更新的库。

注意 要详细了解 Arch 为什么要将 Haskell 包迁移到动态链接,请参阅此 维护者的回复

另一方面,静态链接通常更容易维护,不会迫使您在每次更新依赖项后都从源代码重新构建所有工具,并且目前得到 GHC 的更好支持。出于这些原因,静态链接是本地开发的首选和推荐选项。否则,如果您想要动态链接,为了成功链接,必须将 GHC、Cabal 和 Stack 配置为支持动态链接,因为默认情况下是使用静态链接。

如果您希望将 ghc(来自 官方仓库)与静态链接一起使用,这是可能的,但设置起来更复杂,请参阅 #静态链接

原生安装

要使用 Haskell,请 安装 以下软件包

  1. ghc — Haskell 编译器。有几种 实现 可用,但最常用的(现在是事实上的参考)是 GHC(Glasgow Haskell Compiler)。
  2. cabal-installstack — 依赖 GHC 编译 Haskell 源文件的构建工具。Cabal 是经典的构建工具,专注于依赖解析和来自 Hackage(Haskell 社区的中央开源软件软件包存档)的源代码包。Stack 是另一个构建工具,专注于精选的快照和来自 Stackage(Hackage 的一个稳定子集,提供已知能协同工作的软件包的精选集(快照))的源代码包。
提示 Cabal 和 Stack 都是稳定且成熟的构建工具。许多 Haskell 开发人员使用 Cabal,而许多其他人则偏爱 Stack。如果您不确定选择哪个工具,可以尝试安装两者,看看哪个更适合您。

配置

注意 如果您不打算从源代码编译 Haskell,而只是使用仓库中分发的 Haskell 应用程序,可以跳过本节。

直接调用GHC

为了成功链接,必须将 -dynamic 标志传递给 GHC。您可以使用以下文件进行尝试

Main.hs
main = putStrLn "Hello, World"

使用以下命令编译并运行它

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

为动态链接配置Cabal

首先,运行以下命令从 Hackage 下载最新的软件包列表,并创建全局配置文件 ~/.cabal/config(或 $CABAL_CONFIG 指向的文件)

$ cabal update
提示 建议定期运行 cabal update 以将您本地的软件包和依赖项列表与 Hackage 上的最新版本同步。

要为动态链接配置 Cabal,请在 ~/.cabal/config 中取消注释并编辑以下选项

~/.cabal/config
library-vanilla: False
shared: True
executable-dynamic: True
program-default-options
  ghc-options: -dynamic
  • library-vanilla: False 会抑制静态库的创建(如果您的项目包含库)。
  • shared: True 会启用共享库的创建(如果您的项目包含库)。
  • executable-dynamic: True 会导致为可执行文件使用动态链接(如果您的项目包含可执行文件)。
  • ghc-options: -dynamic 会将 -dynamic 标志添加到每次对 GHC 的调用中(例如,如果一个包有非平凡的 Setup.hs)。

为动态链接配置Stack

您可以使用 stack setup 命令初始化 Stack 并创建全局配置文件 ~/.stack/config.yaml。默认情况下,Stack 在首次调用时会在隔离的位置自动下载自己的 GHC 版本。要强制 Stack 使用系统 GHC 安装,请运行带 --system-ghc--resolver 标志的 stack setup 命令

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

请注意,您需要指定一个与您的系统 GHC 兼容的解析器。否则,Stack 将愉快地忽略 --system-ghc 标志并下载自己的 GHC 副本。您可以使用 ghc --version 命令确定系统 GHC 的版本

$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 8.10.2

然后访问 Stackage 网站,选择一个与您的系统 GHC 版本匹配的长期支持(LTS)或 nightly 快照。在命令行中使用选定的快照作为 --resolver 标志,例如 --resolver lts-16.15--resolver nightly-2020-09-01

Stackage 通常会落后于新的 GHC 版本。可能会出现您系统 GHC 还没有发布对应的 Stackage 快照的情况。在这种情况下,您可能想选择一个较早的 GHC 次要版本的快照,或者暂时降级您的 Haskell 安装,然后等待 Stackage 支持更新的 GHC 版本。

要为动态链接配置 Stack,请将以下片段添加到 ~/.stack/config.yaml

~/.stack/config.yaml
# Stop downloading GHCs into isolated locations under ~/.stack.
install-ghc: false

# Allow Stack to pick the system GHC (false by default).
system-ghc: true

# Allow to use, say, Stackage snapshot for GHC 8.8.2 with system GHC 8.8.3.
compiler-check: newer-minor

# Add the -dynamic flag to every invocation of GHC.
ghc-options:
  "$everything": -dynamic

软件包管理

大多数 Haskell 库和可执行文件都以源代码包的形式分发,可从 Hackage 和 Stackage 获取。Cabal 和 Stack 分别使用这些仓库。

GHC,Haskell 的标准编译器,生成可以在 Linux 上本地运行的机器码。与其他编译型语言一样,Arch 官方仓库中以预构建形式提供了许多流行的 Haskell 包。

一些附加包可以从 AUR 安装。这些包可能需要从源代码构建,构建 AUR 包或开发软件需要安装编译器和构建工具。不建议在此用例中使用 #原生安装 方法,而是参见 #替代安装方式

因此,Haskell 包有四个主要来源:Hackage (Cabal)、Stackage (Stack)、官方仓库AUR

下表总结了不同软件包管理方式的优缺点。

方法 优点 缺点
官方软件仓库
  • 使用 pacman 更方便地管理软件包
  • 已编译为动态链接
  • 并非所有软件包都可用
  • 使从源代码编译变得困难
Cabal
  • 所有软件包都可用
  • 无需 root 权限
  • 对开发支持更好
  • 安装在主目录中
  • 难以移除特定软件包
Stack
  • 所有软件包都可用(倾向于 Stackage)
  • 无需 root 权限
  • 对开发支持更好
  • 安装在主目录中
  • 版本固定到快照
  • 难以移除特定软件包
AUR
  • 附加软件包可用
  • 存在未维护或无人认领的软件包的风险
  • 软件包版本可能不兼容

Cabal

注意 在 Haskell 中,“Cabal”一词可以指
  • 描述 Haskell 包及其依赖项的 Cabal 文件格式;
  • 处理 Cabal 文件格式的 Cabal 库;
  • cabal 命令行工具(由 cabal-install 提供),它使用 Cabal 库来构建 Haskell 包。
在本文档的上下文中,除非另有说明,否则 Cabal 通常指 cabal 命令行工具。

Cabal 是 Haskell 的“原始”构建系统。您可以在 Hackage 上找到的大多数库和工具都可以通过 Cabal 安装。

安装软件包

要运行 Cabal 安装的用户级可执行文件,必须将 ~/.cabal/bin 添加到 $PATH 环境变量

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

运行以下命令一步安装 Hackage 软件包及其所有依赖项

$ cabal install package
警告 如果您使用的是 官方仓库 中的 cabal,截至 2024 年 12 月,Cabal 会忽略 ~/.cabal/config 中的 ghc-options,而在构建 build-type: Custom 的包时。因此,必须在命令行中指定 --ghc-options=-dynamic 标志,否则您可能会遇到构建错误。

您也可以从源代码构建和安装 Haskell 包。为此,在源代码目录中运行不带任何软件包名称的 cabal install

每个 Cabal 包都应该根据 Package Versioning Policy (PVP) 在 .cabal 文件中指定其依赖项列表及其版本约束。在安装软件包期间,Cabal 会尝试找到满足所有约束的依赖项集。这个过程称为依赖解析

Stack 存在是有原因的;Cabal 以给初学者带来很多麻烦而闻名,尽管近年来它已经有所改善。大多数时候依赖解析工作良好,但有时会失败。在这种情况下,您需要找出问题的根源,并给 Cabal 一些关于如何解决有问题的依赖项的提示。例如,有时需要添加 --allow-newer 来允许 Cabal 忽略软件包 PVP 规定的依赖项版本上限,从而有效地安装比软件包作者允许的更新的依赖项。对于维护不善的软件包,情况会更糟;另一个例子是,参见 此线程,其中关于安装 Idris(另一种用 Haskell 编写的编程语言)的讨论,一个人不得不同时使用 --allow-newer--constraint='haskeline < 0.8.0.0' 命令行标志才能成功编译。

移除软件包

没有简单的方法可以做到这一点。Cabal 不支持此功能,但有 cabal-store-gc 等外部工具。

要重新安装整个用户级的 Haskell 软件包系统,请删除 ~/.cabal~/.ghc,然后从头开始。当 GHC 升级时,这通常是必需的。

为了更精确,可以直接在 用户软件包数据库 上使用 ghc-pkg unregister packageghc-pkg hide package/ghc-pkg expose package — 这会让 GHC“忘记”一个已安装的软件包(或假装它不存在)。但这两者都不会删除任何文件。

Stack

Stack 是另一个管理 Haskell 包的工具。它的目标与 Cabal 略有不同,哲学也略有不同。它在底层使用 Cabal 库并与 Hackage 集成——但它在 Stackage 上维护自己的软件包(快照)存储库,并承诺这些快照经过精心策划,并包含协同工作的软件包。

安装软件包

在其默认配置中,Stack 将编译后的可执行文件安装到 ~/.local/bin。在您的 shell 配置文件中,例如 bash~/.bashrczsh~/.zshrc 中,将此目录添加到 $PATH 环境变量。

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

运行以下命令下载、构建和安装 Stackage 软件包

stack install package
警告 截至 2024 年 12 月,Stack 会忽略 ~/.stack/config.yaml 中的 ghc-options,而在构建 Setup.hs 时。如果您在 Setup.hs 中遇到诸如 Could not find module ‘Prelude’ There are files missing in the ‘base-...’ package 之类的构建错误,请尝试安装 ghc-static 包作为一种变通方法。

您也可以通过在软件包目录中运行以下命令,从源代码构建和安装 Haskell 软件包

stack install --resolver resolver

请注意,您应该指定与 stack setup 命令相同的解析器。

移除软件包

Stack 不支持“卸载”操作。

如果您想重新安装整个用户级的 Haskell 软件包系统,请删除 ~/.stack 目录并从头开始。当 GHC 升级时,这通常是必需的。

开发工具

工具

haskell-language-server

haskell-language-server 是 Haskell 的 Language Server Protocol (LSP) 实现。它为任何集成 LSP 的编辑器提供类似 IDE 的功能,如代码补全、“跳转到定义”、悬停文档、代码检查、格式化或重构。

如果您正在使用 pacman 提供的动态链接 Haskell 包,请安装 haskell-language-server。否则,如果您倾向于静态链接,请安装 haskell-language-server-staticAUR。此包包含每个支持的 GHC 版本的静态链接二进制文件。或者,可以通过 ghcupVisual Studio CodeHaskell 扩展 安装 haskell-language-server。

haskell-language-server 将尝试在您打开项目时自动确定构建配置。如果自动检测失败,您可能想使用项目根目录中的 hie.yaml 文件 手动配置

ghcid

ghcid 是一个基于 GHCi 的 Haskell 开发工具,它提供了一种简单而健壮的方式来在每次源代码更改时显示编译器错误和警告。它可以通过 ghcidAUR 包安装。

hoogle

hoogle 允许您按函数名或近似类型签名搜索 Haskell 库。它可以通过 hoogle 包安装。

hoogle 的在线版本可在 https://hoogle.haskell.org 找到。

代码检查工具

hlint

hlint 建议对 Haskell 代码进行可能的改进,例如使用替代函数、简化代码和发现冗余。它可以通过 hlint 包获得。

stan

stan 是一个 Haskell 静态分析器,与 hlint 互补。截至 2025 年 12 月,它处于 Beta 阶段。可在 haskell-stanAUR 中找到。

weeder

weeder 是一个执行全程序死代码分析的应用程序。

代码格式化工具

  • Floskell — hindent 的一个分支,专注于灵活性和可配置性。
https://github.com/ennocramer/floskell || haskell-floskell
  • Fourmolu — Ormolu 的一个分支,增加了配置各种格式化参数的能力。
https://github.com/parsonsmatt/fourmolu || haskell-fourmolu
  • hindent — 可扩展的 Haskell 代码美化器。
https://github.com/mihaimaruseac/hindent || hindent
  • Ormolu — Haskell 源代码格式化器,实现一种“真正”的格式化风格,不允许配置。
https://github.com/tweag/ormolu || haskell-ormolu
  • stylish-haskell — 简单的 Haskell 代码美化工具。
https://github.com/jaspervdj/stylish-haskell || stylish-haskell

编辑器

Visual Studio Code

Visual Studio Code 有一个由 haskell-language-server 驱动的 Haskell 扩展。如果您没有安装 haskell-language-server,Haskell 扩展将自动为您下载并安装静态链接的 Linux 二进制文件。

IntelliJ IDEA

IntelliJ IDEA 对 Haskell 的支持由 Haskell LSP 插件 提供。它适用于 IntelliJ IDEA 的所有版本,包括 intellij-idea-community-edition

您需要安装 Stack 才能在 IntelliJ IDEA 中创建新项目或导入现有项目。截至 2021 年 6 月,Cabal 单独的项目 不支持

Vim

通过 Vimhaskell-vim 插件可以获得基本的 Haskell 语法高亮和缩进。为了获得更好的类似 IDE 的体验,请使用其中一个 LSP 客户端 插件(例如 coc.nvimALELanguageClient-neovim),并结合 haskell-language-server

Emacs

Haskell 的基本 Emacs 支持由官方的 haskell-mode 提供。为了获得更高级的功能,请同时使用 lsp-haskellhaskell-language-server

替代安装方式

本节介绍的方法最适合 Haskell 开发环境。如果情况如此,可以与 官方仓库 中的软件包一起使用,请确保您知道您使用的是哪个版本的 Haskell 软件包,是 pacman 安装的还是通过以下方法之一安装的。

ghcup

这是在任何 Linux 发行版中安装 Haskell 的推荐方法。GHCup 在您的主目录中安装 GHC、工具和库,允许并行安装多个版本并相对轻松地进行管理。它的范围类似于 rustuppyenvjenv

安装 ghcup-hs-binAUR 包。或者,您可以遵循官方 安装说明 或手动下载 ghcup 二进制文件 并将其放置在 $PATH 的某个位置。

默认情况下,ghcup 会将可执行文件安装到 ~/.ghcup/bin。您需要将此目录添加到您的 shell 配置文件中的 $PATH 环境变量,例如 bash~/.bashrczsh~/.zshrc。如果您想运行 Cabal 安装的可执行文件,也请将 ~/.cabal/bin 添加到 $PATH

export PATH="$HOME/.cabal/bin:$HOME/.ghcup/bin:$PATH"
提示 如果您想使用 XDG 风格的目录,请设置 GHCUP_USE_XDG_DIRS 环境变量(https://ghcup.readthedocs.io/en/latest/guide/#xdg-support)。

GHCup 提供了一个方便的 TUI,支持其大部分功能

$ ghcup tui

或者,您可以使用以下 CLI 命令

列出可用的 GHC 和 Cabal 版本

$ ghcup list

安装推荐的 GHC 版本

$ ghcup install ghc

您也可以安装特定版本的 GHC,例如

$ ghcup install ghc 8.10.2

上述命令不会自动使 GHC 在 $PATH 上可用。您需要通过选择默认使用的 GHC 版本来使其生效

$ ghcup set ghc 8.10.2
注意 GHCup 通常与 Cabal 结合使用来管理其他 Haskell 包,您也可以使用它来安装 Stack,请参阅 #Stack

安装推荐的 Cabal 版本

$ ghcup install cabal

GHCup 也可以安装 haskell-language-server,请使用以下命令

$ ghcup install hls

更多信息,请参阅官方 ghcupCabal 文档。

与原生安装一起使用

如果您决定使用 GHCup 和 Cabal 以及本地安装,您需要在 $HOME/.config/cabal/config 中指定 Cabal 使用哪个 GHC,方法是提供要使用的 GHC 版本的路径。搜索 with-compiler: 行并取消注释它。

 with-compiler: path_of_your_ghc

请记住,如果您使用 GHCup,您的 GHC 路径将位于 $HOME/.ghcup/bin 下。同样,GHCup 一旦设置了您想要的 GHC 版本,就会将该版本链接到 $HOME/.ghcup/bin/ghc。如果您在 Cabal 配置中设置了该路径,您就可以使用 GHCup 来更改 Cabal 使用的 GHC 版本。

Stack

您可以使用 stack-binAUR 包或使用 GHCup(请参阅 #ghcup)来安装 Stack。或者,您可以遵循官方的 安装说明 或手动下载 Stack 二进制文件 并将其放置在 $PATH 中的某个位置。

如果您想运行 Stack 安装的可执行文件,请将 ~/.local/bin 目录添加到 $PATH,有关如何执行此操作的更多信息,请参阅 环境变量

Stack 将使用隔离的 GHC 版本,因此不需要任何额外的配置。运行 stack setup 以从最新的 Stackage LTS 快照自动安装 GHC。

$ stack setup

您现在可以使用 Stack 来构建和安装静态链接的 Haskell 包,而无需任何特殊的配置或命令行标志。

$ stack install package

有关更多信息,请参阅官方 Stack 文档

Nix

本文章或章节需要扩充。

原因:由于缺乏经验,我无法提供足够好的概述(请在 Talk:Haskell 中讨论)

完全不同的安装 Haskell 的方法是使用 Nix 包管理器。Nix 的学习曲线更陡峭,但在可靠且可复现的方式下管理 Haskell 和非 Haskell 包方面提供了更大的灵活性。

技巧与提示

静态链接

警告 无法保证其能正常工作,因为仓库中的 GHC 版本非常过时。您可能会遇到目前除了更新 GHC 之外没有其他解决方案的错误 [1]
  • 本节介绍如何在 Arch 上构建静态链接的 Haskell 包,同时仍使用从官方仓库安装的 GHC。在继续之前,请确保删除 ~/.cabal~/.stack 目录(如果它们存在)。
  • 在本文章的上下文中,静态链接并不意味着生成完全静态的 ELF 二进制文件。只有 Haskell 代码将静态链接到一个 ELF 二进制文件中,该文件可能与 glibc 等其他系统库动态链接。

要使用静态链接,至少必须通过 ghc-static 包安装静态引导库。这将允许您构建仅依赖于引导库以及官方仓库中未通过 haskell-* 包安装的任何其他库的项目。

不幸的是,如果您的项目依赖于您已安装的任何动态链接的 haskell-* 包,Cabal 在依赖解析过程中不会考虑缺少静态库。因此,它会尝试使用现有的 haskell-* 包,然后在发现缺少静态库时以 链接器错误 失败。

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.

ghc-static 不同,没有可用于链接的“haskell-*-static”包。不过,还有其他方法可以解决此问题,如下节所述。

静态全局包数据库

官方 ghc-static 包提供了一种直接的 方法,它在 /usr/lib/ghc-version/static-package.conf.d 下公开一个备用的“静态”全局包数据库。静态数据库仅限于可静态链接的引导包,因此如果 Cabal 被重新配置为使用静态数据库而不是默认数据库,它将表现得好像动态链接的 haskell-* 包不存在一样。

静态数据库的精确路径可以在构建时使用类似以下的命令确定:

$ ghc --print-global-package-db | sed 's/\(package\.conf\.d\)$/static-\1/'
/usr/lib/ghc-version/static-package.conf.d

以下是如何启用静态数据库以供使用:

  • 在使用 Cabal 构建包时,可以传递以下标志来将全局包的选择限制为仅引导包。
$ cabal configure --ghc-pkg-option="--global-package-db=$(ghc --print-global-package-db | sed 's/\(package\.conf\.d\)$/static-\1/')"
  • 当直接使用 GHC 而不是 Cabal 进行构建时,可以传递以下标志来覆盖全局包数据库。
$ ghc -clear-package-db -package-db "$(ghc --print-global-package-db | sed 's/\(package\.conf\.d\)$/static-\1/')" -user-package-db ...

ghc-pristine

安装 ghc-pristineAUR 包,它包装现有的 GHC 安装,在 /usr/share/ghc-pristine 中创建一个独立的 GHC 发行版,其包数据库仅包含引导库。这有效地创建了一个不包含动态链接 haskell-* 包的半隔离环境,但仍然利用了官方仓库中的 GHC 编译器。然后,要使用静态链接构建软件,只需调用包装后的编译器 /usr/share/ghc-pristine/bin/ghc。对于 Cabal,这相当于在 ~/.cabal/config 中进行以下配置:

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

您还可以通过从项目目录运行以下命令,在每个项目的基础上指定编译器路径。

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

stack-static

安装 stack-binAUR 包。与 cabal-static 方法类似,请确保您从官方仓库安装的其他 Haskell 包仅限于 ghcghc-libsghc-static。然后在 #Configuring Stack for dynamic linking 中所述,设置 Stack 以使用系统 GHC。

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

要使这些选项永久生效,请将以下代码段粘贴到 ~/.stack/config.yaml 中。

~/.stack/config.yaml
# Stop downloading GHCs into isolated locations under ~/.stack.
install-ghc: false

# Allow Stack to pick the system GHC (false by default).
system-ghc: true

# Allow to use, say, Stackage snapshot for GHC 8.8.2 with system GHC 8.8.3.
compiler-check: newer-minor

此配置将允许您像平常一样构建静态链接的包,但使用系统 GHC 安装而不是 Stack 提供的 GHC。

hpack-static-bin

hpack-static-binAUR 提供了 haskell-hpack 的静态链接(意味着没有 haskell-* 依赖项)替代品。它是预编译的,因此不需要构建依赖项。

参见