函数
函数在Haskell中扮演着重要角色,因为它是一种函数式编程语言.像其他语言一样,Haskell确实有自己的功能定义和声明.
函数声明包含函数名称及其参数列表及其输出.
函数定义是实际定义函数的地方.
让我们以添加函数的小例子来详细了解这个概念.
add :: Integer -> Integer -> Integer --function declaration
add x y = x + y --function definition
main = do
putStrLn "The addition of the two numbers is:"
print(add 2 5) --calling a function
这里,我们在第一行和第二行声明了我们的函数,我们已经写了实际的函数将接受两个参数并产生一个整数类型输出.
与大多数其他语言一样,Haskell开始从 main 方法编译代码.我们的代码将生成以下输出 :
The addition of the two numbers is:
7
模式匹配
模式匹配是匹配特定类型表达式的过程.它只不过是一种简化代码的技术.此技术可以实现为任何类型的Type类. If-Else可以用作模式匹配的替代选项.
模式匹配可以被视为动态多态的变体,在运行时,可以根据参数列表执行不同的方法.
查看以下代码块.这里我们使用模式匹配技术来计算数字的阶乘.
fact :: Int -> Int
fact 0 = 1
fact n = n * fact ( n - 1 )
main = do
putStrLn "The factorial of 5 is:"
print (fact 5)
我们都知道如何计算数字的阶乘.编译器将开始使用参数搜索名为"fact"的函数.如果参数不等于0,那么数字将继续调用相同的函数,其中1比实际参数的函数少.
当参数的模式与0完全匹配时,它将调用我们的模式,即"事实0 = 1".我们的代码将产生以下输出 :
The factorial of 5 is:
120
Guards
Guards 是一个与模式匹配非常相似的概念.在模式匹配中,我们通常匹配一个或多个表达式,但我们使用 guards 来测试表达式的某些属性.
虽然建议使用模式匹配在警卫,但从开发人员的角度来看,警卫更具可读性和简单性.对于初次使用者,警卫看起来与If-Else语句非常相似,但它们在功能上是不同的.
在以下代码中,我们修改了我们的通过使用警卫的概念 factorial 程序.
fact :: Integer -> Integer
fact n | n == 0 = 1
| n /= 0 = n * fact (n-1)
main = do
putStrLn "The factorial of 5 is:"
print (fact 5)
在这里,我们宣布了两个警卫,用"|"分隔并从 main 调用事实功能.在内部,编译器将以与模式匹配的情况相同的方式工作,以产生以下输出 :
The factorial of 5 is:
120
Where子句
其中是关键字或内置可在运行时用于生成所需输出的函数.当函数计算变得复杂时,它会非常有用.
考虑一个场景,其中输入是具有多个参数的复杂表达式.在这种情况下,您可以使用"where"子句将整个表达式分解为小部分.
在下面的示例中,我们采用了复杂的数学表达式.我们将展示如何使用Haskell找到多项式方程[x ^ 2 - 8x + 6]的根.
roots :: (Float, Float, Float) -> (Float, Float)
roots (a,b,c) = (x1, x2) where
x1 = e + sqrt d / (2 * a)
x2 = e - sqrt d / (2 * a)
d = b * b - 4 * a * c
e = - b / (2 * a)
main = do
putStrLn "The roots of our Polynomial equation are:"
print (roots(1,-8,6))
注意我们的表达式的复杂性来计算根的给定的多项式函数.这很复杂.因此,我们使用 where 子句来破坏表达式.上面的代码将生成以下输出 :
The roots of our Polynomial equation are:
(7.1622777,0.8377223)
递归函数
递归是函数重复调用自身的情况. Haskell不提供任何循环任何表达式的功能.相反,Haskell希望您将整个功能分解为不同函数的集合,并使用递归技术来实现您的功能.
让我们再次考虑我们的模式匹配示例,我们计算了一个数的阶乘.查找数字的阶乘是使用递归的经典案例.在这里,您可能会说,"模式匹配如何与递归不同?"这两者之间的区别在于它们的使用方式.模式匹配用于设置终端约束,而递归是函数调用.
在下面的例子中,我们使用了模式匹配和递归来计算5的阶乘.
fact :: Int -> Int
fact 0 = 1
fact n = n * fact ( n - 1 )
main = do
putStrLn "The factorial of 5 is:"
print (fact 5)
它将产生以下输出 :
The factorial of 5 is:
120
高阶函数
到目前为止,我们看到的是Haskell函数将一个类型作为inp ut并生成另一个类型作为输出,这在其他命令式语言中非常相似.高阶函数是Haskell的一个独特特性,你可以使用函数作为输入或输出参数.
虽然它是一个虚拟概念,但在实际程序中,每个函数都是我们在Haskell中定义使用高阶机制来提供输出.如果您有机会查看Haskell的库函数,那么您会发现大多数库函数都是以更高阶的方式编写的.
让我们举一个例子来说明我们将导入一个内置的高阶函数映射,并根据我们的选择使用相同的函数来实现另一个更高阶函数.
import Data.Char
import Prelude hiding (map)
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map func (x : abc) = func x : map func abc
main = print $ map toUpper "www.JS.com"
在上面的例子中,我们使用了Type Class Char 的 toUpper 函数来转换输入变成大写.这里,方法"map"将函数作为参数并返回所需的输出.这是它的输出 :
sh-4.3$ ghc -O2 --make *.hs -o main -threaded -rtsopts
sh-4.3$ main
"TUTORIALSPOINT.COM"
Lambda Expression
我们有时必须在应用程序的整个生命周期中编写一个仅使用一次的函数.为了处理这种情况,Haskell开发人员使用另一个匿名块,称为 lambda表达式或 lambda函数.
没有函数定义被称为lambda函数. lambda函数用""字符表示.让我们看一下下面的例子,我们将输入值增加1而不创建任何函数.
main = do
putStrLn "The successor of 4 is:"
print ((\x -> x + 1) 4)
在这里,我们创建了一个没有名称的匿名函数.它将整数4作为参数并打印输出值.我们基本上只运行一个功能,甚至没有正确地声明它.这就是lambda表达式的美妙.
我们的lambda表达式将产生以下输出 :
sh-4.3$ main
The successor of 4 is:
5