haskell函数

Haskell是一种纯函数式语言。 这意味着Haskell中的函数的行为更接近数学函数。 函数对输入参数进行运算并返回结果。 函数不修改状态。

在这里,我们将通过以下代码片段中提供的示例介绍Haskell函数。

简单的函数和类型推断

让我们从接受单个输入值并输出单个结果的简单函数开始。

  一半x = x / 2 

此函数采用单个值x并将其转换为输入一半的值。 请注意,我们在此处未指定任何类型。 Haskell推断类型。 函数的:t命令显示以下类型签名。

  * HaskellFunctions>:t一半 
一半::小数a => a-> a

这里要注意的关键点是:

  • half 是一个接受类型a的输入并输出类型a的值的函数
  • Haskell推断出类型a 限于Fractional 类型类。
  • 由于我们没有为a明确指定类型,因此Haskell推断出将支持该功能需求的最通用类型。
  • Fractional :info命令表明,它要求支持(/)运算符功能。 该选择基于使用/half 功能。
  * HaskellFunctions>:info分数 
class Num a =>分数 a
(/):: a-> a-> a
配方:: a-> a
fromRational ::合理-> a
{-#MINIMAL fromRational,(配方|(/))#-}
-在`GHC.Real'中定义
实例小数浮点数-在`GHC.Float'中定义
实例分数双精度-在`GHC.Float'中定义

广场

  平方x = x * x 

square 使用* 操作。 这导致推断的类型Num

  正方形:: Num a => a-> a 

Num上的:i向我们表明Num需要*的支持。

  * HaskellFunctions>:i Num 
Num类在哪里
(+):: a-> a-> a
(-):: a-> a-> a
(*):: a-> a-> a
取反:: a-> a
abs :: a-> a
signum :: a-> a
fromInteger :: Integer->一个
{-#最小(+),(*),abs,signum,来自Integer,(取反|(-))#-}
-在`GHC.Num'中定义
实例Num Word-在`GHC.Num'中定义
instance Num Integer-在`GHC.Num'中定义
instance Num Int-在'GHC.Num'中定义
实例Num Float-在`GHC.Float'中定义
实例Num Double-在`GHC.Float'中定义

面积圆

  圆半径= pi *平方半径 

areaCircle 函数调用square 我们刚刚定义的功能。

  * Haskell函数>:t面积圆 
areaCircle ::浮动a => a-> a

请注意,推断的类型类现在不如square通用 作为areaCircle 使用pi Floating定义的常数 类型类。

  * HaskellFunctions>:t pi 
pi ::浮动a => a

:iFloating 表明它扩展了Fractional 类型类。 因此,这里失去了一些普遍性。

  * HaskellFunctions>:i浮动 
class Fractional a =>浮动 a where
pi ::一个
exp :: a-> a
日志:: a-> a
sqrt ::一个->一个
(**):: a-> a-> a
logBase :: a-> a-> a
罪:: ::-> a
cos :: a-> a
棕褐色:: a-> a
asin :: a-> a
acos ::一个->一个
亚当:: a-> a
sinh :: a-> a
cosh :: a-> a
tanh :: a-> a
阿西尼:: a-> a
acosh :: a-> a
亚当:: ::-
GHC.Float.log1p :: a-> a
GHC.Float.expm1 :: a-> a
GHC.Float.log1pexp :: a-> a
GHC.Float.log1mexp :: a-> a
{-#最小pi,exp,log,sin,cos,asin,acos,atan,sinh,cosh,
阿辛,阿科什,阿坦#-}
-在`GHC.Float'中定义
实例Floating Float-在`GHC.Float'中定义
实例Floating Double-在`GHC.Float'中定义

上面讨论的一个重要内容是:

没有显式类型说明的Haskell函数定义尽可能通用。 保持功能尽可能通用,可促进代码重用。

多参数函数与计算

我们已经看到了单参数函数。 Haskell如何支持多参数功能?

在Haskell中,所有函数仅采用一个参数。 多参数功能是通过级联多功能应用程序而形成的。 最好用一个例子来解释。

volumeCylinder

  volumeCylinder rh =面积圆r * h 

上面的函数似乎有两个参数,半径(r)和高度(h)。

  * HaskellFunctions>:t volumeCylinder 
volumeCylinder ::浮动a => a-> a-> a

该功能的签名如上所示。 前两个箭头代表半径和高度参数。 第三个箭头表示返回值。 这在下面进一步阐明。

  volumeCylinder ::浮动 
=>一个-^半径
->一个-^高度
->一个-^体积

看来, volumeCylinder 函数有两个参数。 但是,Haskell将以上声明视为两个函数应用程序的级联:

  • volumeCylinder 函数取半径(r)并返回第二个函数。
  • 第二个函数将高度作为参数,并返回圆柱体的体积。

严格来说, volumeCylinder 签名应如下所示。

  volumeCylinder ::浮动a => a->(a-> a) 

Haskell通过这种方式实现功能,以方便部分应用。 量gauge10Volume解释了部分应用 通过将参数部分应用于volumeCylinder形成的volumeCylinder 功能。

guage10音量

  gauge10Volume ::浮动a => a-> a 
规格10体积=体积气缸(2.58826 / 2)

考虑上述功能,该功能确定给定长度的10号规电缆的体积。 该函数的主体仅由volumeCylinder的部分应用volumeCylinder 只需使用radius参数即可。 gauge10Volume 只需获取高度参数(电缆的长度)并返回10号电缆的体积即可。

运作

+,*等操作也是函数。 这些操作可以在常规的infix操作a+b调用,也可以作为函数(+) ab调用。

  add1 =(+)10 2-添加为函数 
add2 = 10 + 2-中缀添加
  mul1 =(*)10 2-乘以一个函数 
mul2 = 10 * 2-中缀乘法
  floatDiv = 10/4-Haskell除法返回Double 
intDiv1 = div 10 4-div执行整数除法
intDiv2 = 10`div` 4-div的中缀版本

您可以通过在GHCI中的:i命令中发出命令来了解有关功能的更多信息。 您可以看到函数签名以及运算符优先级。

  * HaskellFunctions>:i(+)(-)(*)(/) 
Num类在哪里
(+):: a-> a-> a
...
-在`GHC.Num'中定义
infixl 6 +

  Num类在哪里 
...
(-):: a-> a-> a
...
-在`GHC.Num'中定义
infixl 6-

  Num类在哪里 
...
(*):: a-> a-> a
...
-在`GHC.Num'中定义
infixl 7 *

class Num a =>分数a
(/):: a-> a-> a
...
-在`GHC.Real'中定义
infixl 7 /

使用公式定义的递归函数

Haskell支持函数中的参数模式匹配。 您可以使用不同的参数模式指定同一函数的多个声明。 例如, factorial 函数如下所示,带有两个声明:

  • factorial 0指定数字0的阶乘
  • factorial n定义除0以外的所有整数的阶乘。
  阶乘::积分a => a-> a 
阶乘0 = 1
阶乘n = n *阶乘(n-1)

还要注意, factorial n的定义是根据factorial (n-1)递归定义的。 递归是函数编程中非常常见的模式。 我们将看到它被用于函数定义,数据结构定义和循环。