Haskell - 基本数据模型

Haskell 是一种纯函数式编程语言,因此它比其他编程语言更具交互性和智能性。 在本章中,我们将学习 Haskell 的基本数据模型,这些模型实际上是预定义的或以某种方式智能解码到计算机内存中的。

数字

Haskell 足够聪明,可以将某些数字解码为数字。 因此,您无需像我们通常在其他编程语言中那样在外部提及其类型。 按照示例,转到 prelude 命令提示符,只需运行"2+2"并按 Enter 键。

sh-4.3$ ghci 
GHCi, version 7.6.3: http://www.haskell.org/ghc/  :? for help 
Loading package ghc-prim ... linking ... done. 
Loading package integer-gmp ... linking ... done. 
Loading package base ... linking ... done. 
Prelude> 2+2

您将收到以下输出结果。

4

在上面的代码中,我们只是将两个数字作为参数传递给 GHCI 编译器,而没有预先定义它们的类型,但编译器可以轻松地将这两个条目解码为数字。

现在,让我们尝试一些更复杂的数学计算,看看我们的智能编译器是否给出了正确的输出。 尝试使用"15+(5*5)-40"

Prelude> 15+(5*5)-40 

上述表达式根据预期输出生成"0"。

0

字符

像数字一样,Haskell 可以智能地识别作为输入给出的字符。 转到 Haskell 命令提示符并键入带双引号或单引号的任何字符。

让我们提供以下行作为输入并检查其输出。

Prelude> :t "a" 

它将产生以下输出 −

"a" :: [Char] 

请记住,您在提供输入时使用 (:t)。 在上面的示例中,(:t) 用于包含与输入相关的特定类型。 我们将在接下来的章节中了解有关此类型的更多信息。

看一下下面的示例,其中我们将一些无效输入作为字符传递,这反过来会导致错误。

Prelude> :t a 
<interactive>:1:1: Not in scope: 'a'  

Prelude> a 
<interactive>:4:1: Not in scope: 'a' 

通过错误消息 "<interactive>:4:1: Not in scope: `a'",Haskell 编译器警告我们它无法识别您的输入。 Haskell 是一种所有事物都用数字表示的语言。

Haskell 遵循传统的 ASCII 编码风格。 让我们看一下下面的例子来了解更多 −

Prelude> '\97' 
'a'  
Prelude> '\67' 
'C' 

看看您的输入如何解码为 ASCII 格式。

字符串

字符串只不过是字符的集合。 使用字符串没有特定的语法,但 Haskell 遵循用双引号表示字符串的常规风格。

看一下下面的示例,其中我们传递字符串"www.w3ccoo.com"。

Prelude> :t "www.w3ccoo.com" 

它将在屏幕上产生以下输出 −

"www.w3ccoo.com" :: [Char] 

查看整个字符串如何被解码为仅包含 Char 的数组。 让我们转向其他数据类型及其语法。 一旦我们开始实际练习,我们就会习惯所有的数据类型及其使用。

布尔值

布尔数据类型也像其他数据类型一样非常简单。 看下面的示例,我们将使用一些布尔输入(例如"True"或"False")来使用不同的布尔运算。

Prelude> True && True 
True  
Prelude> True && False 
False   
Prelude> True || True 
True  
Prelude> True || False 
True

在上面的例子中,我们无需提及"True"和"False"是布尔值。 Haskell 本身可以对其进行解码并执行相应的操作。 让我们用"true"或"false"修改我们的输入。

Prelude> true 

它将产生以下输出 −

<interactive>:9:1: Not in scope: 'true' 

在上面的例子中,Haskell 无法区分"true"和数字值,因此我们的输入"true"不是数字。 因此,Haskell 编译器会抛出一个错误,指出我们的输入不是其范围。

列表和列表理解

与其他数据类型一样,List也是Haskell中使用的非常有用的数据类型。 例如,[a,b,c] 是一个字符列表,因此,根据定义,List 是用逗号分隔的相同数据类型的集合。

与其他数据类型一样,您无需将 List 声明为 List。 Haskell 足够智能,可以通过查看表达式中使用的语法来解码您的输入。

看一下下面的示例,它展示了 Haskell 如何处理列表。

Prelude> [1,2,3,4,5] 

它将产生以下输出 −

[1,2,3,4,5] 

Haskell 中的列表本质上是同质的,这意味着它们不允许您声明不同类型数据类型的列表。 任何像 [1,2,3,4,5,a,b,c,d,e,f] 这样的列表都会产生错误。

Prelude> [1,2,3,4,5,a,b,c,d,e,f] 

This code will produce the following error −

<interactive>:17:12: Not in scope: 'a' 
<interactive>:17:14: Not in scope: 'b' 
<interactive>:17:16: Not in scope: 'c' 
<interactive>:17:18: Not in scope: 'd' 
<interactive>:17:20: Not in scope: 'e' 
<interactive>:17:22: Not in scope: 'f'

列表推导式

列表推导式是使用数学表达式生成列表的过程。 看下面的示例,我们使用 [output | range ,condition] 格式的数学表达式生成一个列表。

Prelude> [x*2| x<-[1..10]] 
[2,4,6,8,10,12,14,16,18,20]  
Prelude> [x*2| x<-[1..5]] 
[2,4,6,8,10]  
Prelude> [x| x<-[1..5]] 
[1,2,3,4,5]

这种使用数学表达式创建列表的方法称为列表理解

元组

Haskell 提供了另一种在单个数据类型中声明多个值的方法。 它被称为元组。 元组可以被视为列表,但是元组和列表之间存在一些技术差异。

元组是一种不可变的数据类型,因为我们无法在运行时修改元素的数量,而列表是一种可变的数据类型。

另一方面,列表是同构数据类型,而元组本质上是异构的,因为元组内部可能包含不同类型的数据。

元组由单括号表示。 看一下下面的示例,了解 Haskell 如何处理元组。

Prelude> (1,1,'a') 

它将产生以下输出 −

(1,1,'a') 

在上面的示例中,我们使用了一个带有两个数字类型变量和一个字符类型变量的元组。