You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell新手请教自定义模块导入问题及代码报错排查

Haskell模块导入与编译问题解答

1. SpaceAge.hs 是否需与 Main.hs 同目录?为何默认 Lib.hs 无此问题?

不需要同目录。Stack 默认项目结构有明确规则:

  • src/ 是库代码专属目录,所有放在这里的模块属于项目的「库目标」,Lib.hs 就是默认生成的库模块。
  • app/Main.hs 属于「可执行目标」,默认配置里已经让这个可执行目标依赖了项目的库目标(比如 package.yaml 的 executables 部分,dependencies 会包含你的项目名称)。所以 Main.hs 能直接导入 Lib,本质是通过依赖库目标实现的跨目录模块导入。

把 SpaceAge.hs 移到 app 目录后报错,是因为 Stack 不会把 app 目录当作库源码目录,编译时依然会去 src/ 下查找模块,自然找不到文件。

2. SpaceAge.hs 代码是否存在错误?

你碰到的 parse error on input 'where' 几乎是缩进语法错误导致的。Haskell 对缩进要求极严,where 块的缩进必须比它所属的表达式更深,或者和函数定义的起始位置保持对齐层级。

举个典型错误示例:

ageOn planet seconds = orbitalPeriod * seconds
where
  orbitalPeriod = case planet of
    Earth -> 1.0

这里 where 的缩进和 ageOn 平齐了,正确写法应该是给 where 和内部代码增加缩进:

ageOn planet seconds = orbitalPeriod * seconds
  where
    orbitalPeriod = case planet of
      Earth -> 1.0

另外也检查下是否有遗漏的括号、逗号,或者函数定义未写完就提前写了 where。

3. 是否需要修改 package.yaml?

分两种场景:

  • 如果把 SpaceAge.hs 放在 src/ 下:完全不需要修改默认配置。Stack 会自动扫描 src/ 下的所有模块作为库目标的一部分,只要模块名和文件名一致(文件叫 SpaceAge.hs,模块开头写 module SpaceAge where),且 package.yaml 里可执行目标的 dependencies 包含项目库名(默认已经配置好),Main.hs 就能直接 import SpaceAge。
  • 如果非要把 SpaceAge.hs 放在 app/ 目录:需要修改 package.yaml 的可执行目标配置,在 other-modules 里添加 SpaceAge,示例如下:
executables:
  Ex2-exe:
    main:                Main.hs
    source-dirs:         app
    other-modules:       SpaceAge
    dependencies:
    - Ex2

但更推荐把自定义模块放在 src/ 下,这是 Haskell 项目的标准结构,后续维护更方便。

4. Main.main 是否存在类型错误?

Haskell 程序入口 main 的类型必须是 IO (),这是强制要求。如果你的 main 直接返回了纯数值(比如 main = ageOn Earth 1000),就会因为类型不匹配报错——因为 ageOn 大概率返回的是 Float/Double 这类纯值类型,而非 IO ()。

正确写法需要把纯值包裹在 IO 动作里,比如:

main = print (ageOn Earth 1000)

如果是导入模块错误引发的间接报错,先解决模块导入问题,再检查 main 的类型是否符合要求。

内容的提问来源于stack exchange,提问作者theoreticalmasterrace

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 16:35:17