我是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 是写函数的正确方法吗?
答案 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"
虽然你检查惯用方法是好的,但我建议初学者使用对他来说最好的东西,无论他最了解什么。例如,如果一个(尚未)理解点自由风格,则没有理由强制它。它迟早会来找你。