VSCode 集成 Haskell 环境

4,274 阅读8分钟

Haskell 是一门函数式编程语言。最近想了解下函数式编程,想学习下试试水。但哪曾想到搭建环境花费了好长时间,现在记录下安装过程,为后来者填坑。这可能是最简单的方式了。

安装 stack

推荐使用 stack 工具来安装 haskell 环境,省时省力。它会自动安装 GHC 到单独的目录,还能安装我们所需要的包。

执行以下命令安装 stack

curl -sSL https://get.haskellstack.org/ | sh

假若安装成功,stack --version 可查看到版本号。

Version 2.3.1, Git revision de2a7b694f07de7e6cf17f8c92338c16286b2878 (8103 commits) x86_64 hpack-0.33.0

stack 相关命令

基础命令

  • stack new project-name

    创建新工程。

  • stack setup

    会自动下载编译器,默认在 ~/.stack 目录下,如下图所示。比如我安装的 ghc 版本是 8.8.3,目录在 ~/.stack/programs/x86_64-osx/ghc-8.8.3

    image.png

  • stack build

    编译工程。执行命令后,会看到如下日志。为了方便查看,我将日志用空行隔开了。

    demo1> configure (lib + exe)
    
    Configuring demo1-0.1.0.0...
    
    demo1> build (lib + exe)
    
    Preprocessing library for demo1-0.1.0.0..
    
    Building library for demo1-0.1.0.0..
    
    [2 of 2] Compiling Lib
    
    Preprocessing executable 'demo1-exe' for demo1-0.1.0.0..
    
    Building executable 'demo1-exe' for demo1-0.1.0.0..
    
    [2 of 2] Compiling Main
    
    Linking .stack-work/dist/x86_64-osx/Cabal-3.0.1.0/build/demo1-exe/demo1-exe ...
    demo1> copy/register
    
    Installing library in /Users/liusilan/Documents/workspace/my/haskell/demo1/.stack-work/install/x86_64-osx/914b9a9a241328120895004f416724292e0c1440b907fe13776156c85b4acd23/8.8.3/lib/x86_64-osx-ghc-8.8.3/demo1-0.1.0.0-AM0RJfS73DT2gtF91cLy6f
    
    Installing executable demo1-exe in /Users/liusilan/Documents/workspace/my/haskell/demo1/.stack-work/install/x86_64-osx/914b9a9a241328120895004f416724292e0c1440b907fe13776156c85b4acd23/8.8.3/bin
    
    Registering library for demo1-0.1.0.0..
    
  • stack exec xx-exe

    执行命令。

    stack build 中日志的最后一行 Installing executable demo1-exe in ...,后面跟的就是 exe 的路径。

    按下面的方式执行即可。

    stack exec /Users/liusilan/Documents/workspace/my/haskell/demo1/.stack-work/install/x86_64-osx/914b9a9a241328120895004f416724292e0c1440b907fe13776156c85b4acd23/8.8.3/bin/demo1-exe 
    

辅助命令

  • stack path

    查看 stack 相关路径。

  • stack ghc -- --version

    查看 ghc 版本。

  • stack --resolver ghc-8.6.5 setup

    指定安装 ghc8.6.5 版本。

  • stack config set resolver ghc-8.6.5

    如果安装了多个 ghc 版本,则可通过指定 resolver 来切换 ghc 版本。

编写代码

现在,haskell 的环境已经搭好,可以开始编码了。

交互式编程

在终端输入 stack ghci 即可进入交互式编程模式,ghcihaskell 的解释器。如下图所示:

image.png

虽然通过这种方式比较方便,也可以快速看到结果。但这仅限于简单的编码,在学习的初始阶段还能满足需求。如果要想写些复杂的语句,就不太合适了。

编辑器

因此,选择一个自己熟悉且趁手的编辑器还是很重要的,编码速度会大大提升。由于我用 VSCode 比较多,所以选择了它来配置 haskell 的环境。

在编码时,我们当然是希望有一套类似于 IDE 体验比较好的编程环境,比如代码能自动补全、关键字高亮,错误提示等等。不然干巴巴的一个个字符的敲代码,啥辅助提示都没有,那可太痛苦。

好在 VSCode 提供了 Haskell Language Server 插件,它提供了一系列功能,比如:

  • 代码高亮
  • 自动补全
  • 定义跳转
  • 文档提示
  • 格式化
  • ...

但由于 Haskell Language Server 依赖了 haskell-ide-engine,我们也需要安装它。

下面来介绍如何集成。

VSCode 集成 haskell

安装插件 Haskell Language Server

略过。

编译 haskell-ide-engine

首先简单介绍一下 haskell-ide-engine

它是一个完整实现了 Language Server Protocol 的服务,所以它可以跟任何支持 LSP 的编辑器集成。如果不了解 LSP,可查看我之前写的文章VSCode 使用 LSP 进行 Swift 开发

实际上,它也支持很多编辑器,比如 Sublime TextEmacsAtom 等等。 如果想要了解其提供哪些功能,可点此查看

这里我们通过编译源码的方式进行安装。

// clone 代码
git clone https://github.com/haskell/haskell-ide-engine --recursive

// 编译源码
cd haskell-ide-engine && ./install.hs hie

在编译的过程中,一直遇到 Connection timed out 的问题,如下所示。

HttpExceptionRequest Request {
  host                 = "raw.githubusercontent.com"
  port                 = 443
  secure               = True
  requestHeaders       = []
  path                 = "/commercialhaskell/stack-templates/master/new-template.hsfiles"
  queryString          = ""
  method               = "GET"
  proxy                = Nothing
  rawBody              = False
  redirectCount        = 10
  responseTimeout      = ResponseTimeoutDefault
  requestVersion       = HTTP/1.1
}
(InternalException (HostCannotConnect "raw.githubusercontent.com" [Network.Socket.connect: <socket: 672>: failed (Connection timed out (WSAETIMEDOUT))]))

注意错误可能不一样,我在家安装时,则是如下错误。但是都是网络连接问题。

HttpExceptionRequest Request {
  host                 = "s3.amazonaws.com"
  port                 = 443
  secure               = True
  requestHeaders       = [("Accept-Encoding",""),("User-Agent","Haskell pantry package")]
  path                 = "/hackage.fpcomplete.com/root.json"
  queryString          = ""
  method               = "GET"
  proxy                = Nothing
  rawBody              = False
  redirectCount        = 10
  responseTimeout      = ResponseTimeoutDefault
  requestVersion       = HTTP/1.1
}
 (InternalException (HandshakeFailed (Error_Misc "Network.Socket.recvBuf: resource vanished (Connection reset by peer)")))

后来换了清华大学镜像,重试了几次,就编译成功了。

~/.stack/config.yaml 中添加如下镜像(建议每次参考清华大学镜像里提及的方式,因为它有可能会更新。)。

但此写法要求 stack >= 2.1.1,如果是其他版本,请参考原链接提供的方式。

package-indices:
  - download-prefix: http://mirrors.tuna.tsinghua.edu.cn/hackage/
    hackage-security:
        keyids:
        - 0a5c7ea47cd1b15f01f5f51a33adda7e655bc0f0b0615baa8e271f4c3351e21d
        - 1ea9ba32c526d1cc91ab5e5bd364ec5e9e8cb67179a471872f6e26f0ae773d42
        - 280b10153a522681163658cb49f632cde3f38d768b736ddbc901d99a1a772833
        - 2a96b1889dc221c17296fcc2bb34b908ca9734376f0f361660200935916ef201
        - 2c6c3627bd6c982990239487f1abd02e08a02e6cf16edb105a8012d444d870c3
        - 51f0161b906011b52c6613376b1ae937670da69322113a246a09f807c62f6921
        - 772e9f4c7db33d251d5c6e357199c819e569d130857dc225549b40845ff0890d
        - aa315286e6ad281ad61182235533c41e806e5a787e0b6d1e7eef3f09d137d2e9
        - fe331502606802feac15e514d9b9ea83fee8b6ffef71335479a2e68d84adc6b0
        key-threshold: 3 # number of keys required

        # ignore expiration date, see https://github.com/commercialhaskell/stack/pull/4614
        ignore-expiry: no

注意:这整个就是 config.yaml 的所有内容。这里我也遇到一些问题,添加后 yaml 格式不正确。

如果是跟我一样的新手,打开 config.yaml 应该会看到 template 之类的东西,建议全部删掉,贴上以上内容即可。

如果编译过程中途出现再次出现 Connection time out 问题,建议重试命令。我也是重试 2~3 次后,最后成功了。

当出现如下界面,则说明编译完成。

image.png

默认安装路径在 ~/.local/bin 下。为了方便使用命令,可将 ~/.local/bin 加入到 PATH 变量。现在,我们到 ~/.local/bin 目录下看看,可发现有了 hie 相关内容。

image.png

VSCode 中配置 hie 路径

image.png

此时,VSCodehaskell 集成的环境已经安装完成。

体验环境

重启下 VSCode,打开之前创建的工程。

注意:新建工程/编译工程/执行可执行文件,还是需要通过 stack 相关命令。

如果你看到以下提到的几个功能,那么 hie 则生效了。

  • 当鼠标 hover 到某个关键字时,会有文档说明,如下所示:

    image.png

  • 当输入字符时,会有自动补全,如下所示:

    image.png

  • 当出现问题时,会提示错误,如下所示:

image.png

题外话

看了上述的安装过程一点也不复杂,对吧。但过程中还是踩了不少坑。

其实一开始,我先找到了 这篇文章 作为参考。文章是 2019 年的,经过实践后,看来已经不太适用了。

按照文中的做法,需要安装一些其他的插件,比如 Haskell Syntax Highlighting、Haskell ghc-mod 、haskell-linter、Haskelly。而在安装这些插件依赖的过程中各种报错,烦不胜烦。可能是由于插件没人维护,依赖的 ghc 版本比较低。

后来索性不弄了,另寻他法。最终参照 如何使用 VS Code 開發 Haskell ,只安装 Haskell Language Server 插件,一切都简单了,并且也有以上插件的功能。

另外,Haskell 在 macOS 下的环境搭建 这篇文章还提到了使用 IntelliJ IDEA 来运行 haskell 项目。不过我没有试验成功,有兴趣的可以尝试一下。

参考文章:

www.codercto.com/a/22342.htm…

juejin.cn/post/684490…