附录 A - Haskell 工具链(The Haskell Toolchain)
本附录内容包括:
- 选择编辑器和基础工具
- 安装 GHC、Stack 和 Cabal
- 使用 GHCi 进行交互式探索
- 安装常用辅助工具
- 用 Docker 创建可重复的 Haskell 环境
学习 Haskell 时,语言本身只是其中一部分。要真正编写程序,还需要编译器、构建工具、包管理器、编辑器支持和运行环境。Haskell 工具链有过多个历史阶段,所以初学者经常会遇到一些名字:GHC、GHCi、Cabal、Stack、HLS、Stackage、Hackage。它们各自负责不同工作。
本附录给出一个实用视角:安装能运行本书示例的工具,并理解每个工具在开发流程中的位置。你不需要一次掌握所有细节;先让项目能创建、构建、运行和测试,就已经足够开始。
A.1 工具与编辑器选择(Choosing tools and editor)
Haskell 的核心编译器是 GHC,也就是 Glasgow Haskell Compiler。它负责把 Haskell 源码编译成可执行程序或库。GHC 也附带 GHCi,这是一个交互式环境,可以加载模块、检查类型、快速试验表达式。
构建工具通常有两个选择:
- Cabal:Haskell 官方生态中的构建和包管理工具
- Stack:基于固定包集和项目配置的构建工具
两者都能构建真实项目。Cabal 更贴近官方生态和 Hackage,Stack 更强调可重复构建和 Stackage 快照。本书示例偏向使用 Stack,因为它能用快照固定依赖版本,减少“今天安装的包和作者当时使用的包不一样”这类问题。
编辑器方面,最重要的是安装 Haskell Language Server。它能提供:
- 类型提示
- 跳转定义
- 自动补全
- 编译错误展示
- 简单重构
- 格式化辅助
HLS 可以和 VS Code、Neovim、Emacs、IntelliJ 等编辑器配合使用。只要编辑器支持 Language Server Protocol,通常就能使用 HLS。
一个常见工具组合是:
GHC 编译器
GHCi 交互式求值环境
Stack 项目构建与依赖管理
HLS 编辑器语言服务
Ormolu 格式化工具
Hlint 代码建议工具
初学阶段不需要过度优化工具选择。重要的是让一个最小项目能够稳定运行。之后再根据项目需求补充格式化、lint、测试和性能分析工具。
A.2 安装 Haskell 工具(Installing Haskell tools)
如今推荐使用 GHCup 安装 Haskell 工具。GHCup 可以安装和切换 GHC、Cabal、Stack 和 HLS 版本。它的价值在于统一管理多个工具,而不是让每个工具各自散落在系统里。
安装完成后,通常可以检查版本:
ghc --version
ghci --version
cabal --version
stack --version
haskell-language-server-wrapper --version
如果这些命令都能运行,说明基本工具链已经可用。
A.2.1 运行 Stack 与 GHCi(Running Stack and GHCi)
用 Stack 创建新项目:
stack new hello-haskell
cd hello-haskell
stack build
stack run
stack new 会根据模板创建项目。stack build 下载依赖并编译项目。stack run 构建并运行默认可执行程序。
Stack 项目中最重要的文件通常包括:
package.yaml
stack.yaml
app/Main.hs
src/
test/
package.yaml 描述包名、依赖、可执行程序、库和测试。stack.yaml 描述使用哪个 Stackage 快照和 GHC 版本。
可以用 Stack 启动 GHCi:
stack ghci
进入 GHCi 后,可以输入表达式:
ghci> 1 + 2
3
ghci> map (* 2) [1..5]
[2,4,6,8,10]
查看表达式类型:
ghci> :type map
map :: (a -> b) -> [a] -> [b]
加载或重新加载项目模块:
ghci> :load src/Lib.hs
ghci> :reload
GHCi 是学习 Haskell 的好伙伴。很多时候,与其猜一个函数怎么用,不如在 GHCi 中问它的类型、试几个小例子。
常用 GHCi 命令包括:
:type expr 查看表达式类型
:info name 查看类型类、类型或函数信息
:load file 加载文件
:reload 重新加载当前项目
:browse Module 查看模块导出
:quit 退出
如果项目依赖很多包,直接运行 ghci 可能找不到依赖。使用 stack ghci 可以让 Stack 根据项目配置准备正确环境。
A.2.2 安装其他工具(Installing other tools)
Haskell 生态中有一些常用辅助工具。可以通过 GHCup、Cabal 或 Stack 安装,具体方式取决于当前系统和项目习惯。
HLS 用于编辑器支持。VS Code 用户通常安装 Haskell 扩展,然后确保 haskell-language-server-wrapper 在 PATH 中。
Ormolu 是格式化工具:
ormolu --mode inplace src/**/*.hs
在 PowerShell 中,通配行为和 Unix shell 不完全相同,所以更稳妥的做法是让编辑器保存时格式化,或使用项目脚本统一调用。
Hlint 可以给出风格和简化建议:
hlint src app test
例如,它可能建议把某段显式递归改成标准库函数,或把冗余表达式简化。Hlint 的建议不是法律。它很有帮助,但最终仍要由项目代码风格决定是否采纳。
常用测试命令:
stack test
cabal test all
常用构建命令:
stack build
cabal build all
常用运行命令:
stack run
cabal run exe:program-name
如果项目使用 Stack,就优先使用 Stack 命令。如果项目使用 Cabal,就优先使用 Cabal 命令。混用工具并非不可能,但初学阶段最好避免不必要的复杂度。
A.3 一体化 Docker 文件(All in one Docker file)
有时,本机安装工具并不是最佳选择。例如:
- 团队成员使用不同操作系统
- CI 需要可重复环境
- 本机已有多个 GHC 版本,容易冲突
- 只想快速试验一个项目
这种情况下,可以用 Docker 固定开发环境。
下面是一个简单 Dockerfile:
代码清单 A.1 Haskell 开发环境 Dockerfile
FROM haskell:9.6
WORKDIR /workspace
RUN cabal update
COPY . .
RUN cabal build all
这个镜像基于官方 Haskell 镜像,复制当前项目并构建。对于使用 Stack 的项目,可以换成安装 Stack 的镜像或自行安装 Stack:
代码清单 A.2 使用 Stack 的 Dockerfile
FROM haskell:9.6
WORKDIR /workspace
RUN curl -sSL https://get.haskellstack.org/ | sh
COPY stack.yaml package.yaml ./
RUN stack setup
COPY . .
RUN stack build
可以构建镜像:
docker build -t hello-haskell .
运行容器:
docker run --rm hello-haskell
开发时通常希望把当前目录挂载进容器:
docker run --rm -it -v "%cd%:/workspace" -w /workspace haskell:9.6 bash
在 PowerShell 中,路径写法可能需要调整:
docker run --rm -it -v "${PWD}:/workspace" -w /workspace haskell:9.6 bash
进入容器后,可以运行:
cabal build all
cabal test all
Docker 的优势是可重复,缺点是反馈可能更慢,编辑器集成也更复杂。对于本书学习,推荐优先使用本机工具链;对于团队项目、CI 或需要固定环境的场景,Docker 很有价值。
最后给一个实用建议:把项目需要的命令写进 README 或脚本里。不要依赖团队成员记住所有工具细节。一个清楚的项目通常会说明:
如何安装工具
如何构建
如何运行
如何测试
如何格式化
工具链的目标不是制造仪式感,而是让编写、验证和交付程序更顺畅。
总结
- GHC 是 Haskell 的主要编译器,GHCi 是交互式求值环境。
- Cabal 和 Stack 都能构建项目;初学时选择项目已经采用的工具即可。
- Haskell Language Server 能显著改善编辑器体验。
- GHCi 适合检查类型、试验表达式和加载模块。
- Ormolu 和 Hlint 可以帮助保持代码风格一致,但建议仍要结合项目上下文判断。
- Docker 可以提供可重复构建环境,适合 CI、团队协作和隔离实验。
- 最好的工具链是稳定、可重复、容易运行验证命令的工具链。