最近又又又又开始学习 Haskell,之前学习的时候都使用单文件的形式,这对使用第三方库产生了很大的障碍(最终也没学下去),最近研究了通过 Docker 去配置 Haskell 环境的方式,这里记录一下,并且同时也去使用 Stack 创建空项目和 Yesod 项目、配置 plfa 环境。
前置条件:
- 安装 Docker
- 安装 VS Code,以及 Dev Containers 扩展
- 闲
创建 linux 容器,安装依赖
首先要创建 linux 容器,使用 fedora 做例子:
我曾尝试过 ubuntu 镜像,但其在创建 Yesod 项目的时候遇到奇怪的编码问题(表现在编译 language-javascript 库时 getContents 报错),应该是系统区域相关的玩意被裁剪的原因
| docker run -di -p 8080:8080 --name haskell-container fedora
|
然后打开本机的 VSCode,点击左下角蓝色图标,选择 Attach to Running Container,选择该容器。
打开后,参考https://mirrors.ustc.edu.cn/help/fedora.html,执行:
| sed -e 's|^metalink=|#metalink=|g' \ -e 's|^#baseurl=http://download.example/pub/fedora/linux|baseurl=https://mirrors.ustc.edu.cn/fedora|g' \ -i.bak \ /etc/yum.repos.d/fedora.repo \ /etc/yum.repos.d/fedora-modular.repo \ /etc/yum.repos.d/fedora-updates.repo \ /etc/yum.repos.d/fedora-updates-modular.repo dnf makecache
|
安装 Ghcup,修改 Ghcup,cabal,stack 源
这里参考https://mirrors.ustc.edu.cn/help/ghcup.html。
首先安装 ghc 所需依赖:
| dnf install -y gcc gcc-c++ gmp gmp-devel make ncurses ncurses-compat-libs xz perl
|
执行下面的命令,一路 y 下去:
| curl --proto '=https' --tlsv1.2 -sSf https://mirrors.ustc.edu.cn/ghcup/sh/bootstrap-haskell | BOOTSTRAP_HASKELL_YAML=https://mirrors.ustc.edu.cn/ghcup/ghcup-metadata/ghcup-0.0.7.yaml sh
|
如果上面这个命令出现了奇怪的错误,或许得使用官方的脚本(注意网络):
| curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
|
安装后,尝试执行 ghci:
| ghci> putStrLn "Hello, Happy World!" Hello, Happy World!
|
bingo!
配置 Ghcup,Cabal,Stack 源
这节参考https://mirrors.ustc.edu.cn/help/ghcup.html,https://mirrors.ustc.edu.cn/help/hackage.html,https://mirrors.ustc.edu.cn/help/stackage.html。
(用 vi 或者 VSCode)编辑~/.ghcup/config.yaml
,添加:
| url-source: OwnSource: https://mirrors.ustc.edu.cn/ghcup/ghcup-metadata/ghcup-0.0.7.yaml
|
编辑~/.stack/config.yaml
,添加:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package-indices: - download-prefix: https://mirrors.ustc.edu.cn/hackage/ hackage-security: keyids: - 0a5c7ea47cd1b15f01f5f51a33adda7e655bc0f0b0615baa8e271f4c3351e21d - 1ea9ba32c526d1cc91ab5e5bd364ec5e9e8cb67179a471872f6e26f0ae773d42 - 280b10153a522681163658cb49f632cde3f38d768b736ddbc901d99a1a772833 - 2a96b1889dc221c17296fcc2bb34b908ca9734376f0f361660200935916ef201 - 2c6c3627bd6c982990239487f1abd02e08a02e6cf16edb105a8012d444d870c3 - 51f0161b906011b52c6613376b1ae937670da69322113a246a09f807c62f6921 - 772e9f4c7db33d251d5c6e357199c819e569d130857dc225549b40845ff0890d - aa315286e6ad281ad61182235533c41e806e5a787e0b6d1e7eef3f09d137d2e9 - fe331502606802feac15e514d9b9ea83fee8b6ffef71335479a2e68d84adc6b0 key-threshold: 3
ignore-expiry: true
setup-info-locations: - http://mirrors.ustc.edu.cn/stackage/stack-setup.yaml urls: latest-snapshot: http://mirrors.ustc.edu.cn/stackage/snapshots.json snapshot-location-base: http://mirrors.ustc.edu.cn/stackage/stackage-snapshots/
|
编辑~/.cabal/config
,找到repository hackage.haskell.org
一行,编辑为:
| repository mirrors.ustc.edu.cn url: https://mirrors.ustc.edu.cn/hackage/ secure: True
|
然后执行下列命令:
| mkdir ~/.stack/pantry curl https://mirrors.ustc.edu.cn/stackage/stackage-content/stack/global-hints.yaml > ~/.stack/pantry/global-hints-cache.yaml
|
使用 Stack 创建项目
执行stack new project-name
可以创建空项目,创建后进入该文件夹,执行stack build
检查是否正常。
执行stack build
若出现”Could not load module ‘Distribution.Simple’”的错误,移除~/.ghc/相应版本 GHC/environments/default
应当能解决,参照https://stackoverflow.com/questions/70994294/problem-with-loading-module-distribution-simple。
给 VSCode 安装 Haskell 扩展,打开项目目录并打开特定 hs 文件就应当可以开始编码了,可以尝试打开 src/Lib.hs 文件,起空行输入-- >>> show "Aloha"
,若出现 Evaluate 按钮则证明工作正常。
添加依赖
添加依赖时不要使用 cabal,可能会出现上一节的问题
但这还不够,如果能识别到 Stack 项目的依赖并给与补全才更好。
编辑 package.yaml,在 dependencies 配置下加入 random 依赖:
| dependencies: - base >= 4.7 && < 5 - random
|
然后,执行stack build
,在另起一个文件 Playground.hs,添加下添加下列内容,导入所有所需依赖并点击 Evaluate:
| module Playground ( ) where import System.Random ( uniformR, mkStdGen, RandomGen, StdGen ) import Data.List ( unfoldr )
roll :: RandomGen g => g -> (Word, g) roll = uniformR (1, 6) rolls :: RandomGen g => g -> [Word] rolls = unfoldr (Just . roll) pureGen :: StdGen pureGen = mkStdGen 42
|
不管你能不能跑,反正我是能跑了 w。
一些书籍/框架环境的搭建
使用 Stack 创建 Yesod 项目
参考https://www.yesodweb.com/page/quickstart,执行 stack build
的时候会出错,查询日志发现缺失 zlib 头文件,使用 dnf 安装zlib-static
, zlib-devel
两个依赖即可。
执行完毕后,创建文件src/HelloWorld.hs
,粘贴下面的代码(这类型安全的 html 模板和路由定义,震撼):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-} import Yesod ( warp, mkYesod, whamlet, parseRoutes, Html, Yesod(defaultLayout), RenderRoute(renderRoute) )
data HelloWorld = HelloWorld
mkYesod "HelloWorld" [parseRoutes| / HomeR GET |]
instance Yesod HelloWorld
getHomeR :: Handler Html getHomeR = defaultLayout [whamlet| <p>Hello, Happy World! |]
main :: IO () main = warp 8080 HelloWorld
|
然后,执行stack runhaskell src/HelloWorld.hs
,在本机访问localhost:8080
,若能成功访问,bingo!
The Haskell School of Music
首先安装需要的系统库:
| dnf install -y alsa-lib-devel GLC_lib-devel
|
创建新 stack 项目,编辑 package.yaml 中 dependencies:
| dependencies: - base >= 4.7 && < 5 - Euterpea - HSoM
|
编辑 stack.yaml 中 extra-deps 配置(默认是注释掉的),并配置allow-newer为true:
| allow-newer: true extra-deps: - git: https://github.com/Euterpea/Euterpea2.git commit: 55f78907ad29ce35e7e0b5ca101b60cd0efca555 - PortMidi-0.2.0.0 - HSoM-1.0.0 - UISF-0.4.0.0 - pure-fft-0.2.0
|
为何要修改 stack.yaml 呢?因为这些依赖不在 LTS 里,它们的版本号没有被指定,且Euterpea的最新版不在Stackage里;allow-newer表示无视版本的上界约束。
plfa
参考https://agda-zh.github.io/PLFA-zh/GettingStarted,以及https://schneide.blog/2020/09/21/compiling-agda-2-6-2-on-fedora-32。
执行下面的命令去:
- 安装 git
- 对一个系统库进行链接(Haskell 为什么这么麻烦?)
- 安装 agda
- 获取 agda 标准库和 plfa 库
- 拷贝库到指定位置
| dnf install -y git ln -s /usr/lib64/libtinfo.so.6 /usr/lib64/libtinfo.so stack install Agda-2.6.2.2 git clone --depth 1 --recurse-submodules --shallow-submodules https://github.com/plfa/plfa.github.io ~/plfa mkdir -p ~/.agda cp ~/plfa/data/dotagda/* ~/.agda
|