如何在 2018 年在 Linux 上安装 Haskell(平台或堆栈)?

How to install Haskell (Platform or Stack) in 2018 on Linux?

我正在尝试从 Learn You a Haskell by Miran Lipovača. Both the book and haskell.org recommends installing the Haskell Platform 书中学习 Haskell,但是没有我使用的 Manjaro Linux(基于 Arch)的下载。

我在 2014 年发现了这个 guide 并决定从 Manjaro 的存储库安装软件包。在我想在 Emacs 中使用 haskell-mode 之前,这工作得很好。我对此进行了故障排除,发现这是软件包的问题(主要是 Stack)。

寻找解决此问题的方法,我发现了这个 Reddit thread, which describes ways to install Haskell (not the Platform), and problems with the packages. I followed one of the comments and ended up installing Stack (and GHC) with the script as described here:

wget -qO- https://get.haskellstack.org/ | sh
stack setup
stack update

我的问题与此有关:

  1. 这是 2018 年在 Linux (Manjaro) 上安装功能正常的 Haskell(平台)的推荐入门方法吗?如果不是:the/a 方法是什么?
  2. Haskell 平台包含:GHC、Cabal、Stack 和一些软件包。 GHC和Stack都安装好了,如何通过Stack安装Cabal?
  3. 我需要 Cabal 吗(Stack 似乎有重叠的功能)?
  4. 查看 Haskell Platform 的软件包,我通过如上所述安装 Stack 缺少什么(如果有的话)?查看 $HOME/.stack/programs/x86_64-linux/ghc-tinfo6-nopie-8.2.2/lib/ghc-8.2.2 其中许多似乎已经安装。

你有三个选择。

Haskell 平台

这是一种可能性,但不是一个受欢迎的选择,原因有很多,如果您选择这种方式,您会在适当的时候发现这一点。使用 Stack 或 Nix,您将获得更好的体验并获得 更好的支持。这两个人使用哪个似乎主要与个人喜好有关。它们是不同的野兽,但对于初学者来说,差异不会立即显现出来,因此您能够制作 "informed decision" 的希望很小。随便选一个,稍后再评价。

堆栈

这就是我对想要快速开始使用 Haskell 的任何人(不熟悉 Nix)的建议。时期。您不需要单独安装任何东西,Stack 会为您处理所有 Haskell 的事情。您通常不会直接将 cabal 与 Stack 一起使用。 stack build 在内部使用 cabal,但您无需担心。需要注意的一件事是,Stack 不是包管理器。它是一个构建工具。它通常不会 install 任何东西。然而,它确实获取了它需要的所有依赖项,并将它们与其他内容一起存储在 ~/.stack 中。

尼克斯

这是我个人使用的,所以我可能会有偏见,但我认为从长远来看,这是总体上最好的解决方案。需要注意的是,学习曲线相当陡峭,开始时你有很多机会搬起石头砸自己的脚。

我强烈建议您从 Stack 开始,但随着您继续 Haskell 的旅程,请对 Nix 保持开放的心态。

这是一个(长)备选答案。请注意,我过去也曾向初学者推荐 Stack,但后来我改变了主意。

TL;DR: Haskell 平台或纯 Stack 安装都可以为您提供所需的一切,而您不会 "missing"通过选择一个或另一个来做任何事情。您可能会发现最简单的方法是跳过 Stack 并使用 "Generic" Linux 安装程序安装 Haskell Platform,因为它附带了您需要的一切,并且设置将更接近于LYAH 书。当您在多个项目上进行更认真的开发时,您可以稍后安装 Stack。如果您更喜欢坚持使用纯 Stack 安装,我建议您从 "global project only" 工作流程开始。无论哪种方式,您都可以使用 "haskell-mode" 和下面建议的一些配置修复(包括如果您在仅 Stack 安装的全局项目中工作则需要的关键设置)。

这里是长答案...

堆栈与平台与 Cabal

LYAH 的书早于 Stack,这当然是它没有提及它的主要原因。在 haskell.org,他们建议使用最小安装程序、Stack 或 Haskell 平台。这三种方法都是 2018 年建立工作 Haskell 环境的完全合理的方法。它们在选择将不同版本的编译器 and/or 库隔离到 "sandboxes" 以进行开发工作的方式以及它们 最初 安装的数量方面有所不同,但是其中任何一个 "missing" 都不能按需安装。根据您的选择,您的工作流程会有所不同(见下文)。

Stack 和 Cabal 都是组合包管理器和构建工具。 (Stack 具有实际上 bootstrap 整个 Haskell 安装的附加功能,这就是为什么它本身也是一种安装方法。)当你通过 LYAH 工作时,你实际上不会直接在您自己的项目上使用 "build tool" 功能。 (GHC 的内置构建工具足以构建小型、多模块项目。)您只需要包管理器功能来安装额外的库。

由于 Stack 和 Cabal 分别管理它们的包,如果您使用 Stack,则没有特别需要直接使用 Cabal。如果你愿意,你可以安装它(事实上,Stack 使用 Cabal 来实现一些深奥的功能,比如 "stack solver",并且在这些情况下需要安装它):

$ stack install cabal-install

但是,即使这会将 "cabal" 放入“$HOME/.local/bin”(并且您需要确保它在您的路径中),您会发现你需要跳到 运行 它:

$ stack exec --no-ghc-package-path cabal -- list

就您的 Stack 环境而言,它并没有真正做任何有用的事情。

更新: 关于“$HOME/.local/bin”路径的说明。如果没有现有安装,https://get.haskellstack.org/ 中的安装脚本可能会默认将 Stack 本身安装到 /usr/local/bin/stack。但是,它应该显示一条警告,将 $HOME/.local/bin 放在您的路径中。如果您将来使用 stack upgrade 升级 Stack,它会在那里安装新版本的 stack,如果您安装包含二进制文件的软件包,也会使用该目录。例如,stack install hlint 会将 Haskell Lint 程序 hlint 安装到该目录。因此,最好将它放在您的路径中 /usr/local/bin.

之前的某个位置

堆栈缺少什么

我认为这涵盖了您的前三个问题。最后,安装 Stack 而不是 Haskell 平台后,您缺少的主要内容是,根据设计,Stack 除了 "stack" 本身之外并没有真正在全球范围内安装任何东西。因此,您所有的 Haskell 工作,包括 运行 编译 Haskell 解释器("ghci")或编译器("ghc"),都需要在 Stack 环境中完成,或者使用特定的相应 Stack 命令:

$ echo 'main = putStrLn "Hello, world!"' > Hello.hs
$ stack ghc -- Hello.hs
[1 of 1] Compiling Main             ( Hello.hs, Hello.o )
Linking Hello ...
$ ./Hello 
Hello, world!
$ 

或者使用 "stack exec" 到 运行 适当 Stack 环境中的通用程序。例如,有时 运行 a Bash shell under stack 可能会有帮助,之后事情的表现有点像全局安装的 Haskell 平台环境:

$ stack exec bash
$ ghci
GHCi, version 8.2.2: http://www.haskell.org/ghc/  :? for help
Prelude> :quit
$ ghc -O2 Hello.hs
[1 of 1] Compiling Main             ( Hello.hs, Hello.o ) [flags changed]
Linking Hello ...
$ exit
$ ghc
The program 'ghc' is currently not installed. ...
$

你错过的另一件事是 Haskell 平台默认安装了一大堆公共库,而新的 Stack 环境几乎什么都没有开始(甚至连编译器都没有,在你 运行 stack setup)。在使用 LYAH 时,您可能会发现需要定期安装额外的库。例如,在 输入和输出 一章中,使用随机数的示例(模块 System.Random)将要求您 运行:

$ stack install random

然后重启你的解释器。

推荐使用Haskell平台

因为 Stack 有点复杂,而且您一开始并不真正需要它提供的功能,所以您可能会发现 Haskell 平台在刚开始时更容易使用。 ("Generic" 安装程序应该可以在您的发行版上正常工作。)它随所有安装的东西一起提供,并且您使用它的方式将更接近 LYAH 中描述的方式。加上 haskell-mode,你应该有一个相当不错的 Haskell 环境。

一般来说,同时安装 Stack 和 Haskell 平台应该没有问题(Haskell 平台实际上 包括 堆栈)。 Stack 将在“$HOME/.stack”子目录下单独维护所有内容,因此编译器或包之间不会有任何干扰。请注意,在此设置中,您将使用 cabal 来管理安装在平台端的包,并且 stack - 显然 - 用于管理堆栈端的包。

纯堆栈安装的初学者工作流程

如果您想坚持使用纯 Stack 安装,我可能会建议您在开始时采用以下工作流程:

您将看到对使用 "stack new" 或 "stack init" 创建的 Stack 项目的引用。一开始就避免这些,坚持使用堆栈"global project"。这是隐式项目,当您 运行 "stack" 在没有 "stack.yaml" 文件的目录中(直接或在父目录中)时将生效:

$ cd
$ stack path --project-root
/u/buhr/.stack/global-project
$

当你在全局项目中工作时(即,不在 stack.yaml 文件下的某个地方),你可以调用解释器和编译器:

$ stack exec ghci
$ stack ghc -- -O2 Hello.hs

并且他们都可以访问您使用以下命令安装的任何其他库(包):

$ stack install random

更新: 关于 stack ghcistack exec ghci 之间区别的说明。前者旨在 运行 GHCi 在本地项目的上下文中(即,在 stack.yaml 文件下工作)。它传递一些额外的标志来隐藏全局安装的包并自动从你的包中提供可用的模块。在全局项目中工作时,除了 stack ghci 生成警告外,我认为没有任何实际区别;并且无论您使用哪个,都需要使用 :load Whatever.hs 显式加载您自己的模块。 this Stack documentation page 上有更多关于差异的信息,特别是在试图解释差异的底部。

最终,您可能会切换到使用 Stack 项目的工作流程。这将涉及使用 stack new 创建一个新的 Stack 项目目录,stack setup 到 install/link 私有编译器版本到该目录,然后修改项目的 xxx.cabal 文件(并且可能它的 stack.yaml 文件)来指示需要哪些附加包,而不是使用 stack install。当您只是想开始编写代码时,这一切都有点复杂。

您可能还会看到对 Intero 的引用,这是一种专为 Stack 设计的 Emacs 模式。 Intero 非常好,但在处理全局项目中的文件时效果不是很好。它会倾向于在目录“~/.stack/global-project”中启动解释器,这是非常无用的。 (我使用 Intero,但我已经对其进行了修补以使其在这方面表现得更好。)

配置 Haskell-模式(针对平台或堆栈)

最好坚持使用 "haskell-mode",并在开始使用非全球项目时考虑 Intero。我建议按照说明从 MELPA 安装 "haskell-mode",但将以下内容添加到 .emacs 文件中,而不是文档中建议的内容:

(require 'haskell)

;; add capability to submit code to interpreter and mark errors
(add-hook 'haskell-mode-hook 'interactive-haskell-mode)

;; add missing keybindings for navigating errors
(define-key interactive-haskell-mode-map (kbd "M-n") 'haskell-goto-next-error)
(define-key interactive-haskell-mode-map (kbd "M-p") 'haskell-goto-prev-error)
(define-key interactive-haskell-mode-map (kbd "C-c M-p") 
 'haskell-goto-first-error)

;; merge this with your existing custom-set-variables
(custom-set-variables

 ;; NOTE: include following line to work around haskell-mode
 ;; bug if using GHC >= 8.2.1.
 ;; See: https://github.com/haskell/haskell-mode/issues/1553
 '(haskell-process-args-stack-ghci 
   '("--ghci-options=-ferror-spans -fshow-loaded-modules"
     "--no-build" "--no-load"))

 ;; some options suggested in the haskell-mode documentation
 '(haskell-process-auto-import-loaded-modules t)
 '(haskell-process-log t)
 '(haskell-process-suggest-remove-import-lines t)

 ;; make sure "stack ghci" is used, even in the global project
 '(haskell-process-type 'stack-ghci))

我已经使用 "haskell-mode-20171022.26" 对纯 Stack 安装进行了测试,它似乎工作正常。我可以在全局项目中加载一个新的 Haskell 文件,使用 "C-c C-l" 将其提交到交互式会话,并使用 "M-n" 和 "M-p" 浏览源文件中突出显示的错误。 (错误出现在迷你缓冲区中。)

如果您决定改用 Haskell 平台,我认为所有这些 "haskell-mode" 配置仍然适用,除了您应该删除最后的自定义行。 (auto 的默认 haskell-process-type 会选择合适的。)

希望对您有所帮助!