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
相关产品推荐
相关产品推荐

