# 如何安装 Haskell 工具链？

By [MirrorPoster](https://paragraph.com/@mirrorposter) · 2022-05-01

---

本文介绍如何在类 UNIX 系统上（Linux、MacOS、FreeBSD）从零开始一步步安装 Haskell 工具链（编译器、构建工具、编辑器），特别是考虑到国内特殊网络环境，会介绍如何使用国内源。注意：

*   在 2023 年的今天，Cabal 已经取得了长足进步，因此本文将完全不涉及 Stack。
    
*   如果你使用 Windows，好消息是 Haskell 工具链完整支持 Windows，但超出本文范围之外。尽管如此，本文仍然适用于 WSL。
    
*   目前国内只有上海交大和中科大有 Haskell 工具链的完整镜像（GHCup、Hackage、Stackage）。本文采用中科大镜像，你可以手动修改命令来使用其他镜像。
    

本文的目标读者是对 Haskell 没有任何了解的初学者。

安装 GHCup、GHC 和其他工具
------------------

GHCup 是一个 Haskell 工具链的版本管理器。简单来说，它可用于安装不同版本的 GHC、Cabal、HLS 等工具。

### 准备工作

GHCup 是一个近期出现的工具，因此国内目前只有[中科大](https://mirrors.ustc.edu.cn/help/ghcup.html)和[上海交大](https://mirrors.sjtug.sjtu.edu.cn/docs/ghcup)有镜像。在安装 GHCup 之前，我们要做一件额外的工作，创建 `~/.cabal` 目录，并创建 `~/.cabal/config` 文件，填入如下内容：

    repository mirrors.ustc.edu.cn
      url: https://mirrors.ustc.edu.cn/hackage/
      secure: True
    

这是因为 GHCup 在安装 Cabal 时会进行初始化（会下载一个 100MB 的文件），但此时我们还没有替换 Hackage 源！这一步首先替换 Hackage 源。之后安装过程就会如丝般顺滑。

### 执行安装

在终端中运行如下命令：

    curl --proto '=https' --tlsv1.2 -sSf https://mirrors.ustc.edu.cn/ghcup/sh/bootstrap-haskell | BOOTSTRAP_HASKELL_YAML=https://mirrors.ustc.edu.cn/ghcup/ghcup-metadata/ghcup-0.0.7.yaml sh
    

（是的，一行。）

很快，你会看到如下界面：

![ghcup 安装脚本](https://storage.googleapis.com/papyrus_images/3806d6d64d4a95d5ed1b7a3e3f2b783bfaffbad5cc2d594fcd9f1aa366a24295.jpg)

ghcup 安装脚本

\*\*安装过程请仔细阅读所有提示。\*\*针对三个问题，下面是我的推荐：

1.  \*\*是否将 ghcup 目录加入 PATH？\*\*直接回车接受默认值，如果你在看这篇文章，说明你一定会用到。
    
2.  \*\*是否安装 Haskell Language Server？\*\*安装与否均可，之后想装也很容易。这里输入 Y 安装（你大概是希望使用更高级的 IDE 功能的）。
    
3.  \*\*是否安装 Stack？\*\*输入 N，不安装。
    

之后一路回车，GHCup 将下载安装推荐版本的 GHC 和 Cabal，并完成初始化。（截至本文写作时，GHC 版本是 8.10.7）。结束后，你会看到一大片提示，**请仔细阅读所有输出**。这里必做的事情是设置当前 shell 的 `PATH` （或者重启一下 shell 也行）：

    source ~/.ghcup/env
    

### 测试安装

搞定！你已经可以用起来 Haskell 了。

    $ ghc --version
    The Glorious Glasgow Haskell Compilation System, version 8.10.7
    
    $ cabal --version
    cabal-install version 3.6.2.0
    compiled using version 3.6.2.0 of the Cabal library
    
    $ ghci
    GHCi, version 8.10.7: https://www.haskell.org/ghc/  :? for help
    Prelude> putStrLn "Hello, Haskell!"
    Hello, Haskell!
    Prelude> 
    Leaving GHCi.
    

### 配置 GHCup 源

我们上面用了环境变量临时修改了 GHCup 元数据地址，这里我们把镜像写到配置里让国内源永久生效。修改 ~/.ghcup/config.yaml（如不存在就创建），添加如下内容：

    url-source:
        OwnSource: https://mirrors.ustc.edu.cn/ghcup/ghcup-metadata/ghcup-0.0.7.yaml
    

### GHCup 的用法

`ghcup` 有一个很好用的命令叫 `tui`，所有 ghcup 的操作均可以从这里完成，运行 `ghcup tui` 会显示如下界面。

![ghcup tui](https://storage.googleapis.com/papyrus_images/2ac021b13da008c84964e631e7bfe6a5942e9d0b03007c5cdfd30f9d63764016.jpg)

ghcup tui

其中打**双对勾**的是**当前选中版本**。比如你安装了 GHC 9.2.1 和 GHC 8.10.7 两个版本，但是目前选中的是 8.10.7，那么运行 ghc 命令会调用 8.10.7 版本而非 9.2.1 版本。你可以安装多个版本，但一次只能选中一个版本（用 `s` 键选中别的版本）。好了，剩下的命令都顾名思义，自己试试即可。

如果想安装 HLS 的话，随时可以从这里安装。

配置编辑器
-----

本文的重点不是配置编辑器，下面只给出一些提示。请参阅其他资料（尤其是相应插件自己的文档）了解如何配置、如何使用。

### Visual Studio Code

Visual Studio Code 是目前最流行的代码编辑器之一，Haskell 语言服务器则为 LSP 提供了较好的支持，两者相得益彰。只需在扩展市场中搜索名为 Haskell 的扩展并安装即可。

之后，任意打开一个 .hs 文件，Visual Studio Code 就会自动调用 GHCup 已经安装的 HLS，可以充分体验 Haskell 的 IDE 编辑体验了！（_如果 VSCode 提示你要下载 HLS，请下转故障排除章节。_）

恭喜，至此你已经完成配置了 2023 年最先进的 Haskell 工具链+编辑环境！尽情享受吧！

### Emacs

Emacs 默认没有 Haskell 代码高亮，但可以安装 haskell-mode。它的功能非常丰富，推荐阅读其文档。比如一个很有用的命令是 `haskell-process-load-or-reload` ，可以用来快速打开一个 ghci 并载入当前文件。

如果想要使用 HLS：

1.  先手动通过 ghcup 安装 HLS。
    
2.  再安装 lsp-mode、lsp-haskell。
    

That’s all!

### Vim 和 Neovim

vim 原生支持 Haskell 的代码高亮。要与 HLS 集成，可使用 [coc.nvim](https://link.zhihu.com/?target=https%3A//github.com/neoclide/coc.nvim)。

Cabal 应急生存手册
------------

使用 Haskell 时，**强烈建议首先创建一个项目**。这是因为 Cabal 让使用第三方库非常方便。Cabal 有一个不错的使用指南，值得收藏：

[https://cabal.readthedocs.io/en/3.6/](https://cabal.readthedocs.io/en/3.6/)

### 创建项目

    $ mkdir my-first-haskell-project
    $ cd my-first-haskell-project
    $ cabal init     # 在当前目录下初始化一个 Cabal 项目
    
    Guessing dependencies...
    
    Generating LICENSE...
    Warning: unknown license type, you must put a copy in LICENSE yourself.
    Generating CHANGELOG.md...
    Generating app/Main.hs...
    Generating my-first-haskell-project.cabal...
    
    Warning: no synopsis given. You should edit the .cabal file and add one.
    You may want to edit the .cabal file and add a Description field.
    
    $ tree .
    .
    ├── CHANGELOG.md
    ├── app
    │   └── Main.hs
    └── my-first-haskell-project.cabal
    
    1 directory, 3 files
    

可以看到，Cabal 创建了 3 个文件。其中 CHANGELOG.md 是用来记录版本更新内容的，对初学者来说不用关心。

### 增加第三方依赖

打开 .cabal 文件，除去基本的项目信息外，有一个 `executable` 段落：

    executable my-first-haskell-project
        main-is:          Main.hs               -- 入口文件名
        build-depends:    base ^>=4.14.3.0      -- 依赖
        hs-source-dirs:   app                   -- 代码目录
        default-language: Haskell2010           -- 默认语言
    

其中， `^>=` 对 `base` （Haskell 标准库） 的版本增加了限制。对学习者来说，可以忽视这些限制（直接去掉版本限制）。下面我们增加 [time](https://hackage.haskell.org/package/time') 这个库为一个依赖：

    executable my-first-haskell-project
        main-is:          Main.hs
        build-depends:    base, time     -- 这里添加了 time 库
        hs-source-dirs:   app
        default-language: Haskell2010
    

然后，就可以在代码文件 `app/Main.hs` 中使用了：

    module Main where
    
    import Data.Time.LocalTime   -- 来自 time 库
    
    main :: IO ()
    main = do
      now <- getZonedTime
      print now
    

（补充说明：Cabal 在编译时会自动求解一套互相兼容的包的版本，因此不写版本限制对学习者来说最方便，出问题的概率小了很多。但同时要注意这是不好的开发实践，在发布软件时最好先使用 `cabal gen-bounds` 命令生成兼容的版本范围。尽管不写版本范围让可行解的范围大了不少，但仍然有可能出现不兼容问题——会输出大量令人生畏的报错信息——这多数情况是因为你的某个依赖实在是太旧了，最好换一个新的同类包。）

### 编译、运行和 REPL

    $ cabal build # 编译
    [一大堆输出]
    [1 of 1] Compiling Main [一堆输出]
    Linking ..../my-first-haskell-project
    
    $ cabal run   # 运行
    [cabal run 会自动调用 cabal build，所以这里可能是 Up to date 也可能是和 cabal build 一样的一大堆输出]
    2022-01-11 01:38:32.87706 CST
    
    $ cabal repl
    [一大堆输出]
    *Main>        # ghci，但自动载入 Main 模块，并且可以自由用任何第三方依赖里的模块
    

Cabal 在编译时会自动从 [Hackage](https://hackage.haskell.org/) 上下载并构建第三方依赖。因此你可以自由地在 Hackage 上找自己感兴趣的包，然后加到项目依赖里来实验。比如下面这些好玩的包，可以试试看！

*   gloss, 2D 图形库。
    
*   reanimate, 类似 manim 的动画库。首页有很多酷炫例子。
    
*   gi-gtk-declarative, GUI 库。
    
*   inline-r, 与 R 语言无缝协作。
    
*   Chart, 绘制 2D 图表。
    
*   accelerate, 硬件加速的数组运算库，可以编译到 GPU 上运行！
    
*   ad, 自动微分。
    
*   等等等等……
    

Hackage 上有很多有趣的包，现在都是你的了。

故障排除
====

### 如何彻底卸载？如何彻底重新安装？

    rm -rf ~/.cabal ~/.ghcup ~/.ghc
    

### VSCode 提示我要下载 HLS，但我在 GHCup 那里已经下载过了？

有如下原因：

1.  你没有使用 GHCup 安装 HLS。现在去安装一下？如果还不行，再看下面的。
    
2.  你没有添加 GHCup 的路径到 PATH 中。如果始终不行，参考下面的配置。
    

在 Haskell 扩展页面，点击页面上的小齿轮打开扩展配置。

1.  找到 “Haskell: Server Executable Path” 配置项。
    
2.  输入 `~/.ghcup/bin/haskell-language-server-wrapper` 。
    
3.  重启 VSCode。
    

这时候重新打开文件应该就可以正确调用到 GHCup 安装的 HLS 上了。

### 编辑器提示我 HLS 启动失败，怎么回事？

最可能的原因是你启用了 HLS 目前不支持的新版本 GHC。如果想使用 HLS，请务必在 `ghcup tui` 中选中一个有 hls-powered 标记的 GHC 版本（比如 9.0.1, 8.10.7 等）。

### 其他环境错误

1.  Mac 上安装时，若报错信息中有 `configure` 字样，是因为没有安装 Xcode Command Line Tools。
    
2.  如果步骤“执行安装”中运行命令后提示类似 `curl: command not found`，需要安装curl。Linux 下命令为：`sudo apt install curl`。
    
3.  在 Linux 下可能需要额外安装一些包。以 Linux Mint 20.3（同 Ubuntu 20.04）为例：执行`sudo apt install build-essential libgmp-dev libncurses5-dev libncursesw5-dev` 来安装 gcc、gmp 库、ncurses 库。其他发行版可参照之。
    

* * *

**修订记录**

1.  2023-07-09: 少量格式和字句修正；「2022」更新到「2023」。
    
2.  2022-09-15: 将 ghcup metadata 版本升级至 0.0.7。

---

*Originally published on [MirrorPoster](https://paragraph.com/@mirrorposter/haskell)*
