Stack script interpreter

Stack script interpreter

dramdram

Motivation

N/A

前置知识

你首先需要有 stack

Script

stack 可以解析包括一个特殊标记的注释的 .hs 文件,来运行对应的命令。比如在文件 file.hs 写

-- stack runghc

就代表运行这个程序的正确姿势,是运行这个命令

stack runghc file.hs

写的 script 怎么运行?

直接在命令行

stack file.hs

stack 会自动去调用合适的命令。

我们来仔细说一下各种命令的使用方法:

runghc

在你的文件顶端(在 module 声明和所有 {-# LANGUAGE #-} 之上),加上这样的两行

#!/usr/bin/env stack
-- stack runghc

就好了。用法和普通的 runghc 几乎是一样的(你得有 main 函数啥的),只不过会多一些 stack 管理环境的便捷,和更多的一些功能:

上面那个 shebang 就是给用 Unix-like 系统的人用的。看得懂的人,自然知道我在说什么。

为 script 指定依赖项

首先,你大概会知道有个东西叫 Stackage snapshot。我们用 --resolver 来指定,这个程序使用哪个 snapshot。

-- stack runghc --resolver lts-8.9

然后可以指定需要用到哪些包。既然我们都钦定了 snapshot 了,版本就可以不管了。

--package turtle

当然如果你想的话,可以写上。这样还可以调用在 Hackage 上却不在 Stackage 上的包,同时保证版本固定。

--package acme-missiles-0.3

为了严格检查我们确实写出了所有依赖,我们可以用 ghc 的参数 -hide-all-packages,这样所有我们没写进依赖的包的 module 都不能用。(-hide-all-packages 的意思,你可以认为是“所有包默认隐藏”)

那么此时我们连 base 都要写上了。写过 Cabal 包的应该知道你的程序要依赖 base 就要写上。

但是我怎么知道每个参数是传给 stack 还是 ghc 的呢?方法是,用 -- 分割,前面的给 stack,后面的给 ghc

所以我们的程序上面多了这么两行

#!/usr/bin/env stack
-- stack runghc --resolver lts-8.9 --package base --package turtle --package acme-missiles-0.3 -- -hide-all-packages

多行参数

把这些参数全写成一行太难看了啊,但是我们可以这样:

#!/usr/bin/env stack
{- stack runghc
--resolver lts-8.9
--package base
--package turtle
--package acme-missiles-0.3
--
-hide-all-packages
-}

{-# LANGUAGE OverloadedStrings #-} -- 这是有关 turtle 的事情啦

import Turtle
import Acme.Missiles

main = do
    echo "Hello World"
    launchMissiles

这样我们就成功写出了一个完整的,依赖也标出来了的小程序。

这样在使用 stack file.hs 的时候,stack 就会帮你下载 snapshot 的 build plan,把依赖全都安装上,然后运行你的程序。如果之前装过依赖的话就不会重复安装了。

其他一些东西

exec ghci

把 runghc 换成 exec ghci,然后启动 stack file.hs 的时候,就会开一个 ghci,里面加载了你的程序。同样,依赖会给你装好。这个在开发 script 的时候特别常用,因为你不用把你的所有要做的事情全都挤进 main 里面了。此外,如果你只是想写几个函数玩玩,那么也应该用 exec ghci。

exec ghc

更奇怪的一个做法是,直接在 stack file.hs 的时候,编译你的程序。这样就不会有 runghc 的解释,typecheck 什么的 overhead 了。写一些常用小工具的时候有用。

我一般会把 -o 到什么可执行文件写上

#!/usr/bin/env stack
{- stack exec ghc
...
--
-hide-all-packages
-o my-awesome-utility
}

还有两个我不用的东西

--install-ghc

如果你希望在运行你的 script 的时候,如果没有对应的 ghc 的话,也要安装 ghc,那么为 stack 指定 --install-ghc。我一般不会指定这个参数,因为我这儿下 ghc 要好久,而且还不一定一次能装上。

script

理论上来说,应该用 script 命令,来强制制定 --resolver 和 -hide-all-packages 什么的,但是 stack script 为了保证运行结果在哪儿都一样,不去读 config,于是清华 TUNA 镜像就用不了,非要从 s3 上下包,然后就没法用了。所以我不用。

还是详见 stack 的文档好


题图是 「Vampire Princess」/「月影ネム@お仕事募集中」

文章被以下专栏收录
2 条评论
推荐阅读