在Haskell中定义函数的正确方法

时间:2012-01-01 13:29:20

标签: haskell

我是Haskell的新手,我正在尝试一些教程。 我写了这个剧本:

lucky::(Integral a)=> a-> String
lucky 7 = "LUCKY NUMBER 7"
lucky x = "Bad luck"

我把它保存为lucky.hs并在解释器中运行它并且工作正常。

但我不确定函数定义。从我读过的小小看来,我可以同样定义幸运函数如下(函数名称为lucky2):

lucky2::(Integral a)=> a-> String
lucky2 x=(if x== 7 then "LUCKY NUMBER 7" else "Bad luck")

两者似乎同样有效。显然函数 lucky 更清晰,但是 lucky2 是写函数的正确方法吗?

2 个答案:

答案 0 :(得分:15)

他们都是正确的。可以说,第一个是更惯用的Haskell,因为它使用了非常重要的功能,称为模式匹配。在这种形式中,它通常写成:

lucky::(Integral a)=> a-> String
lucky 7 = "LUCKY NUMBER 7"
lucky _ = "Bad luck"

下划线表示您忽略参数的确切形式(值)。您只关心它与7不同,后者是您之前声明所捕获的模式。


模式匹配的重要性最好通过对更复杂的数据(例如列表)进行操作的函数来说明。例如,如果您要编写一个计算列表长度的函数,则可能首先为空列表提供变量:

len [] = 0

[]子句是一种模式,设置为匹配空列表。空列表显然长度为0,所以这就是我们的函数返回。

len的其他部分如下:

len (x:xs) = 1 + len xs

在这里,您匹配模式(x:xs)。冒号:是所谓的 cons运算符:它将值附加到列表中。因此,表达式x:xs是一种模式,它匹配某些列表(x)附加的元素(xs)。总的来说,它匹配一个至少包含一个元素的列表,因为xs也可以是一个空列表([])。

len的第二个定义也非常简单。您计算剩余列表的长度(len xs),并将其计算为1,它对应于第一个元素(x)。

(编写上述定义的通常方法是:

len (_:xs) = 1 + len xs

这再次表示你不关心第一个元素是什么,只是它存在)。

答案 1 :(得分:7)

第三种方式是使用警卫:

lucky n
    | n == 7    = "lucky"
    | otherwise = "unlucky"

没有理由对此感到困惑。总有一种方法可以做到这一点。请注意,即使没有模式匹配或保护并且您 使用if,也是如此。

到目前为止,我们所涵盖的所有形式都使用Haskell提供的所谓语法糖。模式保护转换为普通的案例表达式,以及多个函数子句和if表达式。因此,写这个的最低级,没有粗略的方式可能是:

lucky n = case n of
     7 -> "lucky"
     _ -> "unlucky"

虽然你检查惯用方法是好的,但我建议初学者使用对他来说最好的东西,无论他最了解什么。例如,如果一个(尚未)理解点自由风格,则没有理由强制它。它迟早会来找你。