📜  Haskell-函数

📅  最后修改于: 2020-11-04 06:57:46             🧑  作者: Mango


函数在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是一个与模式匹配非常相似的概念。在模式匹配中,我们通常匹配一个或多个表达式,但是我们使用防护来测试表达式的某些属性。

尽管建议在警卫使用模式匹配,但是从开发人员的角度来看,卫士是更具可读性和简单。对于初次使用的用户,警卫看上去与If-Else语句非常相似,但是它们在功能上有所不同。

在以下代码中,我们通过使用guards的概念修改了阶乘程序。

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”子句将整个表达式分解成小部分。

在下面的示例中,我们采用一个复杂的数学表达式。我们将展示如何使用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函数将一种类型作为输入,并产生另一种类型作为输出,这在其他命令式语言中非常相似。高阶函数是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 "tutorialspoint.com" 

在上面的示例中,我们使用了Type Class ChartoUpper函数将输入转换为大写。在这里,方法“ map”将一个函数作为参数并返回所需的输出。这是它的输出-

sh-4.3$ ghc -O2 --make *.hs -o main -threaded -rtsopts
sh-4.3$ main
"TUTORIALSPOINT.COM" 

Lambda表达

有时,我们必须编写一个在整个应用程序生命周期中只能使用一次的函数。为了应对这种情况,Haskell开发人员使用了另一个称为lambda expressionlambda 函数的匿名块。

不具有定义的函数称为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