配置 Haskell 开发环境(2023)
本文章面向北京大学《计算概论A(实验班)》课程,也适用于其他想要学习 Haskell 的朋友们。
说明:这并不是一篇纯粹的安装指南,其中会包含大量的废话以及对大一的朋友们的忠告。 配置环境将是一直伴随你们的梦魇,本文的目的除了告诉你们怎么做以外,还会讨论为什么要这么做。 更纯净的安装指南可以参考去年助教的文章配置Haskell开发环境(2022), 请注意时效性问题。
我们将要逐一完成下面的任务:
- 安装 GHCup(和 MSys2)
- 使用 GHCup 安装 GHC 和其它工具链
- 安装 VSCode 并配置 Haskell 开发环境
需要注意的是,如果你涉及如下情况,你的安装将可能是失败的:
- 用手机安装 Haskell
- 所在地没有网络
- 你的用户名是中文
为什么用户名不能是中文?
这与字符编码等问题相关。很多专业软件对路径的读取是不支持中文的,这就好比我们写一个软件也不会优先考虑阿拉伯语的用户一样。 例如,在Windows中,如果你使用一个中文的用户名如“王富贵”,那么你的个人用户的路径将是“C:\Users\王富贵\”, 那么软件在读取你的个人目录(以保存应用配置等文件)时就会出错。
除此之外,安装软件时也尽可能选择英文路径。推荐的安装路径如“D:\Software”,不推荐的安装路径如“D:\软件”(在安装Python时可能会遇到这个问题) 一些炫酷的用户名如“꧁༺ᵒᯅᵒ༻꧂”也不建议使用,出了问题只能折磨自己。
安装 GHCup
GHCup 是一款 Haskell 安装工具, 可以安装特定版本的 GHC、stack、cabal、HLS,并可以帮助管理多个 Haskell 版本共存的环境。 我们按照官网给出的方法安装 GHCup,并使用 GHCup 完成后续的安装。
如果你是 Linux、macOS、FreeBSD 或 WSL,执行如下命令:
curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
如果你是 Windows,执行如下命令:
Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; try { Invoke-Command -ScriptBlock ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1 -UseBasicParsing))) -ArgumentList $true } catch { Write-Error $_ }
建议打开这个链接点击页面右侧的按钮直接复制命令。请不要以管理员身份执行上述命令。
我应该在哪里执行上面的命令?
如果你是 macOS,通过“Command + 空格”聚焦搜索,输入“终端”或“Terminal”,然后打开; 如果你是 Windows,点击开始旁的搜索,输入“powershell”,注意不要以管理员的方式运行。 你将得到一个朴素的经常出现在电影里的窗口,复制上面的命令并回车执行。 如果你是 macOS,通过“Command + V”进行粘贴,如果你是 Windows,在黑色窗口任何位置右键即可粘贴。
此外,macOS 用户可以考虑安装 iTerm,Windows 用户建议安装 PowerShell 7,并可以考虑安装 Windows Terminal。它们的安装不在本教程中涉及。
我看到其他教程没有使用 GHCup?
在阅读网上的教程时,一定要注意文章的时效性,包括你正在阅读的这篇文章! 如果你搜到了2017年左右的文章,它会推荐你使用 Haskell platform; 如果你搜到了2020年左右的文章,它可能推荐你使用 stack 安装 Haskell; 而2023年,使用 GHCup 则是最好的方法。
当然 GHCup 不是唯一安装 Haskell 的方法,在此不再赘述使用 GHCup 的好处。
在你执行命令后,你应当看到如下的内容:
接下来理想情况下,我们应该跟随 GHCup 的脚步完成 Haskell 的整个安装:
- 安装 GHCup 自身;
- 安装 msys2(仅 Windows 用户);
- 安装 Haskell 相关工具链。
当前命令行等待你提供一个 GHCup 的安装路径,默认为C:\
,输入回车即可。
建议使用默认的路径。如果一定要自选路径,那么我希望你知道自己在做什么以及出了问题后应该怎么做,且路径不要有中文。
之后会让你提供 cabal 的安装路径,我们依旧选取默认路径。
而后安装程序会询问你是否要安装 HLS(默认为不安装),我们输入Y
并回车表示安装;
stack 和 MSys2 同理选择安装。
安装 GHCup 和 MSys2
而后我们可以看到下载进度,首先会下载并安装 GHCup 和 MSys2:
安装完成后,GHCup 会试图进行后续的安装,即安装上文所说的 cabal 等等。
(如果你是 Windows,那么会弹出一个新的窗口。)
考虑到国内的网络情况,我们在这一步的安装过程中大概率发生如下错误。
其大致含义就是在下载 https://raw.githubusercontent.com/haskell/...
这个文件时失败了。
下面我们要进行换源。
在换源之前我们需要首先保证我们的 GHCup 已经安装成功了。
重新打开一个终端,输入 ghcup --version
并回车,如下给出 ghcup
的版本号则是成功了。($
符号表示提示符,后面的文本是需要输入的命令,不以$
开头的行是程序显示的输出)
$ ghcup --version
The GHCup Haskell installer, version 0.1.19.4
在这一步下载失败了应该怎么办?
输入上面的命令重试 ^_^(你在期待什么)。在命令行中,你可以按“上方向键”来快速地获取你的上一条命令。
这句命令是什么意思?
就像我们在图形界面里双击运行程序一样,在命令行运行程序就要输入它的名字(PATH 相关问题不在此展开)。
--version
是程序运行的参数,由程序自身定义并处理。
这里的参数告诉 ghcup 我要查看你的版本,ghcup 返回输出结果:0.1.19.4。
你可以通过输入 ghcup --help
来查看 GHCup 的使用方式,以及各个参数的含义。
注意并不是所有参数都以 --
开头。
例如在后文中我们会使用到 ghcup install ...
这样的命令。
一般而言,不以 --
开头的代表程序的主要功能;反之可以看作是程序运行的选项。
如果你输入了一些程序无法处理的参数,例如运行 ghcup pku
,
它会输出 Invalid argument `pku'
。
最后再次注意,如何处理参数完全是由程序自己决定的,
例如你也可以写个程序要求参数必须是 pku>thu
,这里说的只是一般的惯例。
给 GHCup 换源
什么是换源?
简单来说,源是在你想要找什么东西的时候去哪找。 但是这个地方你往返可能很不方便,速度很慢,下载东西非常折磨。 镜像站就是其他人把源的东西拷贝了一份,你本来想找的东西在镜像站也能找到了, 东西是一样的,你选择一个你最方便的镜像站找就可以了,也就是换源。
我们这里推荐使用中科大的源。
Windows 用户编辑 C:\ghcup\config.yaml
文件(用记事本打开即可);
macOS 用户编辑 ~/.ghcup/config.yaml
(前往个人文件夹,如果其中没有 .ghcup
,需要首先在文件夹中点击 Command+Shift+。
以显示隐藏文件和文件夹)。
内容如图所示:
在最后添加如下内容并保存:
url-source:
OwnSource: https://mirrors.ustc.edu.cn/ghcup/ghcup-metadata/ghcup-0.0.7.yaml
安装 Haskell 相关工具链
重新在终端中执行命令 ghcup list
,可以看到如下输出(部分内容被截去):
这里列出了所有可用的版本,左侧为“X”代表未安装,“I”代表已安装,“IS”代表已安装并作为默认工具链版本。 右侧为 recommended 代表推荐安装的版本,lastest 代表最后一个版本。 我们在这里安装推荐版本。请所有同学在此安装推荐版本。 逐一执行下面的四条命令(其他读者请注意版本号的时效性),同时我会简单介绍我们安装的是什么。
- 安装 GHC。GHC(Glasgow Haskell Compiler)是 Haskell 最主流的编译器。
ghcup install ghc 9.2.8
- 安装 cabal。cabal 是 Haskell 的一款包管理器。
ghcup install cabal 3.6.2.0
- 安装 stack。stack 也是 Haskell 的一款包管理器。
ghcup install stack 2.9.3
- 安装 HLS。HLS(Haskell Language Server)提供了 IDE 支持,方便程序员的开发。
ghcup install hls 2.2.0.0
什么是编译器?Haskell 只有这一种编译器吗?
简单来说,编译器就是将你写的程序变为计算机能够识别的二进制格式。
你可能知道 C++ 常用的编译器有很多,如 G++、Clang、MSVC 等。 Haskell 当然也有其它的编译器,如 JHC、UHC。然而 GHC 是最广泛使用的。 我们建议所有人使用 GHC。
什么是包管理器?
包管理器是一种工具,允许你安装和管理其他库和依赖。 包/库是其他人写好的实现了某种功能的代码,你可以直接复用它而不需要自己从头实现。 然而一个包可能依赖其他特定版本的包。包管理器就可以帮助我们处理好这些版本和依赖关系。
cabal 和 stack 的区别是什么?我都需要安装吗?
cabal 和 stack 都是 Haskell 常用的包管理工具,这也就意味着必然有一些关于 cabal 和 stack 哪个更好的争论。
首先 cabal 可以帮助你配置和发布 Haskell 项目,这就像 Python 中的 pip、JavaScript 中的 npm、Rust 中的 cargo。cabal 可以提供依赖解析的功能,但是如果出现复杂依赖情况(菱形依赖)就会导致错误,这种情况一般被称为“cabal 地狱”。
stack 实际上是依赖于 cabal 的,stack 会在 build 过程中生成依赖项的固定版本,并避免了菱形依赖的问题, 这意味着你总是可以对旧的项目进行复现。此外,stack 可以管理多个 GHC 版本并总是可以使用正确的版本。
注意看,stack的一个重要的好处是可以管理多个 GHC 版本。 然后你就会惊奇的发现这件事情 GHCup 也可以做啊! 是这样的,如果是在两年前,我会毫不犹豫地推荐 stack。 如今,cabal 修改了解析依赖的方法,cabal + GHCup 的管理方法在社区中反馈也较为积极。 因此我无法给出哪种更好的回答。
当然,完成大型 Haskell 项目对于还在安装 Haskell 的朋友们来说还是太早了。 由于在课上我们会使用到 stack,因此笔者建议安装 GHCup、cabal、stack 全家桶。
在其中的一步下载失败了应该怎么办?
重试这一步的命令 ^_^(你在期待什么)。在命令行中,你可以按“上方向键”来快速地获取你的上一条命令。
在安装好上面的工具链之后,我们可以重新使用 ghcup list
来查看安装情况,在我这里的情况如下所示:
设置默认工具链版本。我们将上面安装的版本都设为默认,在上图中 cabal 3.6.2.0 左侧为“IS”,代表为默认版本; 而 ghc 9.2.8 左侧为“I”,代表仅安装,而未被设置为默认版本。我们通过以下命令完成:
ghcup set ghc 9.2.8
cabal、stack、HLS 类似。
测试上述工具安装情况
如同我们在上文中检查 GHCup,我们重新打开一个终端,并逐一下面的四条命令。
再次注意,$
后为输入的命令。
$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 9.2.8
$ cabal --version
cabal-install version 3.6.2.0
compiled using version 3.6.2.0 of the Cabal library
$ stack --version
Version 2.9.3, Git revision ...
我们也可以输入 ghci
命令来进行交互式运行 Haskell 程序。
如下图所示,红框圈起来的是我们的输入。GHCi 的使用我们将在后续介绍。
安装并配置编辑器
安装 VSCode 以及名为 Haskell 的官方扩展(这个扩展会使用前面安装的HLS)。不推荐安装其它 Haskell 和 GHC 相关的扩展 (Haskell Syntax Highlighting 除外,它会在你安装 Haskell 的时候自动安装)。 如有需求,可以安装Chinese (Simplified) (简体中文) Language Pack for Visual Studio Code扩展。
不建议使用 code-runner 扩展来运行 Haskell 程序。其对 Haskell 的支持并不好,作为给 C/C++/Python 玩家的忠告。
写在最后
到此为止,Haskell 及其开发环境到此就全部完成了。希望读者不要机械地完成上面的指令,而是尝试理解一下每一步是在做什么。 本教程面向无计算机基础以及只接触过 OI 的朋友们,因此讨论了很多基础概念。如果有什么依旧难以理解或有错误的地方,欢迎提出指正。如果在安装过程中遇到任何问题,可以随时在课程群或私聊中反馈。希望你这一次的环境配置一切顺利。