haskell-ghc-mod在sublime text 4中失效因st4移除python 2支持,而ghc-mod依赖其运行时;应改用haskell-language-server(hls)配合lsp插件,并配置hie.yaml与hls.yaml启用完整类型提示、on_save检查及正确模块索引。

为什么 haskell-ghc-mod 插件在 Sublime Text 4 中基本失效
Sublime Text 4 移除了对 Python 2 的支持,而旧版 haskell-ghc-mod 严重依赖 Python 2 的运行时和 subprocess 行为。即使强行安装,也会在调用 ghc-mod 时卡死、崩溃,或返回空提示——类型信息不显示、错误不内联、跳转定义失效。
真正可用的替代路径是绕过 ghc-mod,直接对接 haskell-language-server(hls):它原生支持 LSP 协议,与 Sublime 的 LSP 插件兼容性好,且类型推导、hover 提示、错误定位全部基于 GHC 9.x 实际编译器流水线。
- 确认已安装
haskell-language-server(推荐用ghcup安装,版本需匹配项目 GHC 版本,例如ghcup install hls 2.2.0) - 在 Sublime 中通过 Package Control 安装
LSP插件(非LSP-haskell,后者已废弃) -
LSP插件启用后,需手动配置LSP.sublime-settings,指定haskell-language-server可执行路径,例如:"haskell": { "command": ["haskell-language-server", "--lsp"], "enabled": true, "initializationOptions": { "haskell-file-watch": true } }
如何让 hover 类型提示显示完整签名(含约束、多态变量)
默认情况下,haskell-language-server 的 hover 响应会做“友好裁剪”:省略 forall 量词、折叠 (Eq a, Show b) => 约束、把 a -> (b -> c) 写成 a -> b -> c。这对初学者友好,但破坏了类型推导的精确性。
要还原完整签名,必须关闭 HLS 的“type pretty-printing”优化:
- 在项目根目录创建
hie.yaml,内容为:cradle: direct: arguments: [] - 然后在
hie.yaml同级新建hls.yaml(HLS v2.1+ 支持),加入:plugins: ghcide: typecheck: showFullTypes: true - 重启
LSP服务(快捷键Ctrl+Shift+P→LSP: Restart Servers)
此时 hover 到 map 会显示 forall a b. (a -> b) -> [a] -> [b],而非简化的 (a -> b) -> [a] -> [b];约束也完整展开,比如 sort :: forall a. Ord a => [a] -> [a]。
编译错误反馈延迟高、不实时?检查 haskell-language-server 的触发模式
Sublime 的 LSP 默认使用 “on_type” 触发语义检查,即仅在输入字符后延迟 500ms 扫描。但 Haskell 编译错误往往依赖整模块解析,单行编辑常导致类型环境错乱,进而掩盖真实错误或报出误报。
更稳的方式是切换为 “on_save” 模式,并配合增量构建:
- 在项目级
sublime-project文件中添加:"settings": { "LSP": { "haskell": { "settings": { "haskell-language-server": { "options": { "checkOnSave": true, "checkOnSaveTimeout": 10000 } } } } } } - 确保项目有
.cabal或package.yaml,否则hls会退化为单文件模式,无法跨模块推导类型 - 若仍延迟,检查
haskell-language-server是否被其他进程占用(如终端里还在跑ghcid),hls不允许多实例共享同一dist-newstyle缓存
为什么 import 补全失败或跳转到 GHC 源码而非本地模块
这是路径解析优先级问题。haskell-language-server 默认按如下顺序查找模块:当前项目 > cabal store > global package DB > GHC boot libraries。如果本地模块名与某个已安装包重名(比如你写了 Data.List.Extra,而系统装了 extra 包),HLS 会优先跳转到包内定义。
解决方法不是改名,而是显式声明模块归属:
- 在
hie.yaml中明确 cradle 类型为cabal或stack,例如:cradle: cabal: - path: "./src" component: "lib:myproject" - 确保
cabal file的other-modules:字段包含所有本地模块(哪怕没被主模块 import),否则 HLS 不索引它们 - 补全时按
Ctrl+Space后,观察下拉项右侧标注:带[local]的才是当前项目模块,[package]是第三方包
最易被忽略的一点:HLS 的模块索引只在首次打开项目或修改 hie.yaml 后重建,中途增删模块文件不会自动刷新——必须手动重启 LSP 服务器或重启 Sublime。











