尝试了一些函数调用之后,紧接着了解一下函数的定义,这与调用的形式类似,只是多了函数行为的定义:
函数名 参数1 参数2 参数3 参数4 ... = 函数行为
例如:
doubleIt x = x * 2
doubleThem x y = (x + y) * 2
将这两个函数定义语句保存在一个 .hs
文件中,例如 /Users/Meniny/func.hs
。
然后将终端工作目录切换到 (cd
) 该目录,进入 GHCi
并执行 :l func
命令:
Haskell> :l func
[1 of 1] Compiling Main ( func.hs, interpreted )
Ok, modules loaded: Main.
Haskell> doubleIt 9
18
Haskell> doubleThem 2 3
10
Haskell> 2 `doubleThem` 3
10
Haskell> doubleThem 2 3 + doubleIt 9
28
Haskell>
与主流语言 (例如 C) 不同的是,在我们的 func.hs
中,函数定义的顺序对程序并没有影响。
此外,你当然也可以在你的函数行为定义中调用其它函数,比如我们的 doubleThem
还可以这样写:
doubleThem x y = doubleIt x + doubleIt y
在实际应用中,函数行为并不会总是这么简单,下面我们尝试一些复杂的函数:
amIOldEnough x = if x >= 18
then True
else False
这个函数可以判断你输入的年龄是否大于或等于 18:
Haskell> amIOldEnough 18
True
Haskell> amIOldEnough 10
False
Haskell>
与多数语言不同的是,else
部分是不可省略的,因为 Haskell
程序事实上是一个函数的集合,这些函数将数据作为参数,处理转换为结果,也就是说,这里的 if
事实上是一个必然返回结果的表达式 (Expression
),而不是语句 (Statement
)。
当然,那些换行是不必要的。
伴随着函数定义出现的,通常还有函数类型说明,也叫声明:
函数名 :: 参数类型1 -> 参数类型2 ... -> 参数类型n -> 返回类型
例如,一个求整数平方的函数:
square :: Integer -> Integer
square n = n * n
这写代码表明,square
函数接受一个整数参数,处理后返回一个整数结果,其处理过程为将输入参数乘以自身,即平方。
类似的,也可以接受更多参数:
squaresum :: Integer -> Integer -> Integer
squaresum x y = x * x + y * y
对于函数名,在 Haskell
中使用单引号 '
是合法的,例如:
someFunction' x = x + 1
another'function x = x + 2
give'me'a'strng = "This is Ezra."
使用起来并没有什么不同:
Haskell> someFunction' 2
3
Haskell> another'function 3
5
Haskell> give'me'a'string
"This is Ezra."
Haskell>
但是,通常 '
符号被用来区分这是某个函数的严格求值版本 (相对于惰性求值),或稍有不同的版本。
此外,为了应对更多种情况,我们也会使用守卫 (guard
) 来进行区分:
函数名 参数1, 参数2 ... 参数3
| 守卫条件1 = 结果1
| 守卫条件2 = 结果2
...
| otherwise = 结果n
例如:
max :: Integer -> Integer -> Integer
max x y
| x >= y =x
|otherwisr = y
有些情况下,在 guard
条件中,可能多次进行重复的计算:
arealevel :: Double -> Double -> String
arealevel w h
| w * h <= 1 = "Tiny"
| w * H <= 10 = "Small"
| w * H <= 100 = "Normal"
| w * h <= 1000 = "Big"
| otherwise = "Huge"
显然,仅仅是本例中简单的 w * h
计算,多次书写也已经十分繁琐了,更不方便代码维护。这时候,就要用到 where
:
arealevel :: Double -> Double -> String
arealevel w h
| a <= 1 = "Tiny"
| a <= 10 = "Small"
| a <= 100 = "Normal"
| a <= 1000 = "Big"
| otherwise = "Huge"
where a = w * h
最后,你也许已经注意到了,我们的函数定义都以小写字母开头,这是因为 Haskell
中 函数名不能以大写字母开头。