1

问题 1

出于改善 haskell 编译时间的原因(无论是否使用底层功能,都会编译包含的任何模块),是否有任何工具可以警告 haskell 程序员包含不必要的模块?例如假设我们有以下设置:

必要模块1.hs

module NecessaryModule1 where

addNumber1 :: Int -> Int -> Int
addNumber1 a b = a + b

必要模块2.hs

module NecessaryModule2 where

addNumber2 :: Int -> Int -> Int
addNumber2 a b = a + b

测试.hs

module Test where

import NecessaryModule1
import NecessaryModule2

主文件

module Main where
import Test

myadd :: Int->Int->Int
myadd a b = a + b

main::IO()
main = print(myadd 5 6)

然后这样的工具会警告您有不必要的模块:

  • Main.hs :因为没有使用 Test 的功能
  • Test.hs :因为没有使用 NecessaryModule1 和 NecessaryModule2 的功能


问题2

如果我通过以下方式编译上面的代码:

ghc -o testProg Main.hs

然后我得到一个 833504 字节的可执行文件大小。但是,如果我将Main.hs更改为:

主文件

module Main where
--import Test

myadd :: Int->Int->Int
myadd a b = a + b

main::IO()
main = print(myadd 5 6)

然后可执行文件大小减少到 833057。鉴于 Test 模块的功能未在Main.hs中使用,为什么可执行文件大小有所不同?

4

1 回答 1

3

Q1 Haskell 无法警告您未使用的模块,因为将来它们可能会被另一个包导入。但是,当您导入模块时,只会链接您导入的模块,因此,如果您使用从未导入的模块创建可执行文件,则该模块将不会包含在可执行文件中,除非您明确告诉cabal链接它。

-fwarn-unused-imports当您实际导入模块时,如果您在编译时传递标志,GHC 会警告您不要使用该模块。您还应该考虑使用-Wall,这将启用此警告和许多其他有用的警告。使用-Werror将使 GHC 拒绝编译带有警告的模块,例如未使用的导入或死代码。

您还可以将标志传递-split-objs给 GHC,这将使 GHC 为每个函数(或多或少)创建一个目标文件,而不是每个模块一个目标文件,从而可以显着减少可执行文件的大小。

Q2模板 Haskell 语言扩展可以浏览模块的本地范围作为其某些功能的一部分。因此,GHC 有必要在编译模块时包含显式导入的代码,因为可能有一些 TH 功能依赖于它。启用某些级别的优化(如-O2)可能应该再次剥离未使用的代码,但不能保证。

您可能会考虑使用-shared编译标志进行编译,这将使用共享库进行编译并大大减少整体二进制文件的大小,但如果您想在不同的计算机上使用已编译的二进制文件,则必须同时复制库文件。

于 2012-08-18T14:19:12.337 回答