Haskell 环境搭建指南
HoshinoTented
2019-07-25 12:37:56
Haskell 是一款 纯函数式 的语言,我个人也热衷于 Haskell
下面就来介绍一下如何搭建 Haskell 的环境
# GHC
ghc 是 Haskell 的编译器,就像 gcc 和 C 关系一样
接下来就介绍如何在各个平台安装 ghc
## Linux
以 Ubuntu(APT) 为例,需要在命令行输入以下代码:
```bash
sudo add-apt-repository -y ppa:hvr/ghc
sudo apt-get update
sudo apt-get install -y cabal-install-<version> ghc-<version>
```
其中,cabal 是用于管理 Haskell 依赖库的程序,而 ghc 则是 Haskell 的编译器
更详细的内容都在[这里](https://www.haskell.org/downloads/linux/)
## Windows
首先从[这里](https://www.haskell.org/platform/windows.html)下载 GHC,然后安装
# Stack
但安装原版 ghc 并不是在我们 haskell 之旅中的一个好的选择
比如原版 ghc 在更新时时常会出现一些问题,而且 cabal 的包管理机制也并不是很完善
这个时候,亲身体验了这些风霜的 haskeller 们站了出来,于是便有了 stack
## 如何安装 Stack
首先要找到 stack 的官方网站: [https://haskellstack.org](https://docs.haskellstack.org/en/stable/README/)
![](https://cdn.luogu.com.cn/upload/pic/65723.png)
### Linux/MacOS 用户
只需要在控制台里输入
```bash
curl -sSL https://get.haskellstack.org/ | sh
```
就能够安装 stack
### Windows 用户
需要在官网下载安装包(即上图的 `Windows 64-bit Installer`,这个过程可能会比较缓慢,可以通过虚拟专用网络加速这个过程),随后双击打开
![](https://cdn.luogu.com.cn/upload/pic/65707.png)
自行选择安装路径,之后点击 `Next`
![](https://cdn.luogu.com.cn/upload/pic/65708.png)
下面的两个选项最好勾选,可以自动添加环境变量,少去了自己配置的麻烦
再点 `Install` 就可以完成安装了
## Stack 初始化
安装完 stack 后,打开命令行,输入以下指令
```bash
stack setup
```
用于初始化 stack,可能需要一点时间
## 为 Stack 修改源
stack 的官方源在中国大陆可能会非常慢,因此我们需要修改 stack 的源
请根据你的系统来找到相应的 stack 目录:
* Windows: `C:\sr`
* Linux/MacOS: `~/.stack`
在 stack 目录下找到名为 `config.yml` (如果没有就自己新建一个) 的配置文件,输入以下内容:
```yml
# hackage
package-indices:
- name: Tsinghua
download-prefix: http://mirrors.tuna.tsinghua.edu.cn/hackage/package/
http: http://mirrors.tuna.tsinghua.edu.cn/hackage/00-index.tar.gz
# stackage
setup-info: "http://mirrors.tuna.tsinghua.edu.cn/stackage/stack-setup.yaml"
urls:
latest-snapshot: http://mirrors.tuna.tsinghua.edu.cn/stackage/snapshots.json
lts-build-plans: http://mirrors.tuna.tsinghua.edu.cn/stackage/lts-haskell/
nightly-build-plans: http://mirrors.tuna.tsinghua.edu.cn/stackage/stackage-nightly/
```
这里使用的是[清华大学](https://mirrors.tuna.tsinghua.edu.cn/)的镜像
之后,就可以愉快地初始化 stack 了
# Stack 安装依赖库
stack 安装依赖库十分简单,只需要:
```bash
stack install <libaray name>
```
之后稍加等待,就能安装依赖库了
# GHCi
ghci 是 Haskell 的交互式命令行,具有强大的功能
可以通过 `stack ghci` 进入 ghci
在 ghci 中输入以下内容
```haskell
putStrLn "hoshino so cute!"
```
会输出
```plain
hoshino so cute!
```
当然,你可以通过 `Tab` 来快速补全
ghci 还提供了一些内置命令,这里列举出常用的
* `:type` 或 `:t`
输出目标的类型
例如 `:t foldr`
输出 `foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b`
* `:info` 或 `:i`
输出目标的详细内容
例如 `:t foldr`
输出
```haskell
class Foldable (t :: * -> *) where
...
foldr :: (a -> b -> b) -> b -> t a -> b
...
-- Defined in ‘Data.Foldable’
```
* `:kind` 或 `:k`
输出目标的 `kind`
例如 `:k Functor`
输出 `Functor :: (* -> *) -> Constraint`
* `:set`
设置一些内置功能
`:set +t` 可以在每个值计算完后输出它的类型
`:set +s` 可以在每个值计算完后输出所使用的时间和空间
* `:load` 或 `:l`
载入目标 Haskell 文件
例如: `:l hello.hs`
之后就可以使用 `hello.hs` 中提供的函数了
* `:reload` 或 `:r`
重新载入文件
可以快速重新载入,就不需要重新 `:l` 了
* `:module` 或 `:m`
导入库
例如 `:m +Data.List` 可以导入 `Data.List` 库
`:m -Data.List` 可以取消导入
`:m Data.List` 会取消导入其他库,然后再导入 `Data.List` 库
* `:quit` 或 `:q`
退出 ghci
# IDE 环境
编写程序,IDE 当然是能够提高开发效率的一环,接下来就介绍几个常用 IDE 的 Haskell 支持
## VSCode
`VSCode` 有 依赖官方开发的 `haskell-ide-engine` 的 `haskell language server` 和 `dramforever` 开发的 `Simple GHC Integration`
`haskell language server` 安装麻烦,而且内存占用也比较大,但功能较为强大
`Simple GHC Integration` 一键式插件,新手友好,功能完善
## IntelliJ
`IntelliJ IDEA` 有 `intellij haskell`
个人觉得不太好,所以不多加描述
# Stack Project
可以通过 `stack new <project name>` 来新建一个项目
随后可以看到这样的项目结构:
```plain
.
├── app // 程序代码目录
│ └── Main.hs
├── ChangeLog.md
├── LICENSE
├── my-project.cabal
├── package.yaml // 包配置文件
├── README.md
├── Setup.hs
├── src // 库代码目录
│ └── Lib.hs
├── stack.yaml // stack 配置文件
└── test // 测试代码目录
└── Spec.hs
```
在 `Lib.hs` 中写入以下代码(代码来自[我的博客](https://blog.hoshino9.org)):
```haskell
module Lib (mergeSort) where
import Data.List
-- 归并排序 :: 数组 -> 排序后的数组
mergeSort :: (Eq a, Ord a) => [a] -> [a]
mergeSort (x:[]) = [x] -- 如果是 只有一个元素的数组, 就返回这个数组
mergeSort xs = merge (mergeSort $ fst subs) (mergeSort $ snd subs) -- 把 (被归并排序过的 前半部分的数组) 和 (被归并排序过的 后半部分的数组) 进行排序合并
where
mid = length xs `div` 2 -- 中心的下标
subs = splitAt mid xs -- 把数组分割成两个接近等份(奇数数量情况)或等份(偶数数量情况)的数组
-- 排序并合并两个数组 :: 数组 -> 另一个数组 -> 合并后的数组
merge :: (Eq a, Ord a) => [a] -> [a] -> [a]
merge [] ys = ys -- 如果有任意一个数组为空, 则返回非空的那个数组
merge xs [] = xs
merge (x:xs) (y:ys) = if
x < y then x : merge xs (y:ys) -- 如果 第一个数组的首元素小于 第二个数组的首元素, 则 排序剩下的两个数组, 并将 第一个数组的首元素添加在排序后的数组之前
else y : merge (x:xs) ys -- 这里跟上面差不多啦
```
然后在 `Main.hs` 中写入以下代码,来调用 `src/Lib.hs` 中的函数:
```haskell
module Main where
import Lib
main :: IO ()
main = print $ mergeSort [5, 2, 1, 4, 3]
```
最后,在项目根目录下
在命令行中输入以下内容:
```bash
stack build
```
等待之后,就成功编译这个项目了
然后通过
```bash
stack exec <project-name>-exe
```
来运行编译好的程序
会看到输出: `[1, 2, 3, 4, 5]`
如果在项目目录下运行 `stack ghci`
还会发现自动编译并导入了所有的文件
# 结束语
后续我还会带来关于 Haskell 的更多内容
如果期待的话,可以关注我