What’s GHC ?

GHC(Glasgow Haskell Compiler): an interactive and batch compilation system for the Haskell 98 language.

GHC has two main components: an interactive Haskell interpreter (also known as GHCi), and a batch compiler, described throughout. In fact, GHC consists of a single program which is just run with different options to provide either the interactive or the batch system.

What’s GHCi ?

GHCi是一个GHC的交互式环境,在GHCi中可以交互式地求得对Haskell表达式的值,Haskell程序也可以在GHCi中被解释。GCHi还包含了一个交互式的Haskell调试器。

GHCi的常用命令:

  • :? 或 :help 获取关于GHCi的帮助。
  • :q 或 :quit 退出GHCi。
  • :! 执行外部命令
  • :l 和 :r 或 :load 和 :reload 加载外部的hs文件。
  • :t 或 :type 显示出表达式的类型。
  • :set + t 设置所有表达式默认显示出其类型。
  • :i 显示相关的信息(info)。可以通过这种方式获取帮助。例如:
Prelude> :i print
print :: Show a => a -> IO() -- Defined in 'System.IO'
Prelude> :i +
class Num a where
  (+) :: a -> a -> a
  ...
        -- Defined in 'CHC.Num'

GHCi 使用

在GHCi的使用中,应该注意以下几点:

  • GHCi 中可以直接进行数学表示式的运算,在这一点上和Python的交互式环境(Python Shell) 很像。
  • GHCi 中支持的数学运算符号:+, -, *, /, **(乘方)。注意:**计算得到的结果是浮点数:

      Prelude> :t 2 ** 2
      2 ** 100 :: Floating a->a
    
  • Haskell中不同类型的数不能直接进行数学运算。需要做类型转换。
    • fromIntegral函数可以将整数类型转换为别的类型。
    • toIntegral函数可以将其他类型的数(如:浮点数)转换成整数。
    • 类似的函数还有:fromInteger,toInteger
  • GHCi 中,不能用 % 进行取模运算
  • GHCi 中,/=表达不等号。举例:

      Prelude> 10 /= 20
      True
      Prelude> 10 /= 10
      False
    
  • GHCi 有一个名为 it 的变量,自动保存上一次计算的结果。 其类型也随上一条表达式的结果的变化而变化。

GHCi交互式环境与加载hs文件的区别

如果加载一个hs文件,GHCi会将整个文件看作一个过程,其解释顺序是不可预测的。但是,在GHCi中直接输入表达式是,其解释顺序是由输入(IO)的顺序的决定的。例如:

c = a + b
a = 1
b = 2

将这段代码写在hs文件中,在load进GHCi中后,执行c可以正常输出3,但在GHCi中,无法通过直接输入表达式来得到这样的结果。这也是Haskell的函数式的特性所决定的。

GHCi 与函数

在GHCi中输入加减乘除等表达式时都是在调用函数,+, -, *, / 等都是函数。因此,有如下的用法:

Prelude> (+) 1 2
3

除此以外,还有这些函数可以使用:

  • succ 函数

      Prelude> succ 1
      2
      Prelude> succ 'a'
      'b'
    
  • maxmin 函数

前面提到的/表示的真除法(和Python类似),如果只想保留结果的整数部分(和C++类似),那么可以使用div函数:

Prelude> div 10 3
3

显然,这种形式并不便于理解和区分除数和被除数,因此,可以写成中缀函数的形式(注意 div 左右各有一个”`“符号):

Prelude> 10 `div` 3
3

前面提到,在GHCi中,不能用 % 来表示取模运算,可以这样实现取模:

Prelude> mod 10 3
1
Prelude> 10 `mod` 3
1

GHCi 中定义变量

在GHCi中使用let来定义变量:

Prelude> let a = 1
Prelude> a
1

在GHCi中用let定义变量与在hs文件中通过用=赋值来定义变量是等价的。例如:

a = 1

在GHCi中,如果直接使用=对变量赋值会出错。

GHCi 自动补全

在GHCi中输入命令时,输入命令的前几个字符后,按Tab键便可以补全命令。如果有多个相匹配的命令,GHCi会在下一行列出这些命令。如果只有一个,会直接补全。

Haskell注释语法

  • 单行注释: -- xxx
  • 多行注释: {-- xxx --}

在GHCi中定义函数

在GHCi提供的交互式环境下,也可以定义具有显式类型声明(explicit type declarations)的函数。

例子:

numUniques :: (Eq a) => [a] -> Int
numUniques = length . nub

在GHCi中可以写成是:

let numUniques' :: (Eq a) => [a] -> Int; numUniques' = length . nub

GHC Profiler

运行Haskell程序时加上+RTS -s参数,可以得到profiler统计结果。

      80,084,528 bytes allocated in the heap
          11,696 bytes copied during GC
          42,680 bytes maximum residency (2 sample(s))
          18,760 bytes maximum slop
               1 MB total memory in use (0 MB lost due to fragmentation)

                                    Tot time (elapsed)  Avg pause  Max pause
  Gen  0       152 colls,     0 par    0.00s    0.00s     0.0000s    0.0001s
  Gen  1         2 colls,     0 par    0.00s    0.00s     0.0002s    0.0003s

  INIT    time    0.00s  (  0.00s elapsed)
  MUT     time    0.03s  (  0.04s elapsed)
  GC      time    0.00s  (  0.00s elapsed)
  EXIT    time    0.00s  (  0.00s elapsed)
  Total   time    0.05s  (  0.04s elapsed)

  %GC     time       0.0%  (4.5% elapsed)

  Alloc rate    2,562,704,896 bytes per MUT second

  Productivity 100.0% of total user, 123.3% of total elapsed

使用+RTS -S(大写的S)选项可以输出GC的Trace。

使用GHC编译时加上-rtsopts选项有助于生成更好的Profiler报告。