美高梅官方网站66159

【美高梅线上平台游戏】Haskell未有被猛烈得谈起,先介绍一下Haskell的语法和一部分基本知识

作者:美高梅线上平台游戏    来源:未知    发布时间:2020-04-29 14:42    浏览量:

亮点:Haskell迅速接近前20

这一系列的笔记主要参考中文版的 Real World Haskell,这篇博文作为本系列的第一篇,先介绍一下Haskell的语法和一些基本知识。

Haskell是一种通用的,纯函数式编程语言,
其中包含了很多编程语言研究领域中的新概念。
Haskell提供了高阶函数,非严格语义(non-strict semantics),静态多态类型,
用户自定义的代数数据类型,模式匹配,列表解析(list comprehension),
模块系统,monadic IO系统。

上个月我们问道哪种语言将会成为下一个新的热门语言?我们提出了Scala,Erlang和Clojure。很明显,新语言来自函数式编程领域。一 种面向过程的语言,Haskell没有被明显得提及。这个月它从35名上升到25名。从Tiobe趋势图来看,从2006年到2010年,再到2012 年,它再不断的上升,看起来很有前景。obj-c上升势头依然很猛。


Haskell包含了丰富的原始数据类型,
包括列表,数组,任意精度的整数,以及浮点数。

1–20名:

进入/退出交互模式ghci

安装好Haskell,命令行敲ghci进入交互模式

Prelude> :set prompt “ghci>”
ghci>:q                       -- 退出

Haskell是非严格(non-strict)函数式语言领域,多年研究的结晶。

美高梅线上平台游戏 1

基本算术

ghci> 1 + 1
2

ghci> (+) 1 1
2

ghci> 2 + (-1)     -- 负数是通过唯一的一元操作符'-'得到,-1的括号不能省略
1

ghci> True && False
False

ghci> True || False
True

ghci> :info (+)      -- 操作符的信息可以通过':info'方式查看
class Num a where
  (+) :: a -> a -> a
  ...
    -- Defined in ‘GHC.Num’
infixl 6 +           -- infixl代表加法是左结合的,优先级为6

ghci> :info (^)
(^) :: (Num a, Integral b) => a -> b -> a   -- Defined in ‘GHC.Real’
infixr 8 ^        -- 乘方是右结合的,指数b的类型是Integer,优先级为8

ghci> not True    -- not是一个内置函数,不可以通过:info查看其信息
False

ghci> 1 == 1
True

ghci> 1 /= 1
False

ghci> let e = exp 1     -- 添加绑定
ghci> e ^ 1
2.718281828459045
ghci> e ** pi      -- 指数不是整数时,需要更换操作符
23.140692632779263

21--50名:

列表和元组

列表表示一系列相同类型的元素集合,元组则可以包括不同类型的元素,void在Haskell中被实现为一个空的元组

ghci> [1,2]    -- 列表
[1,2]

ghci> [1..5]
[1,2,3,4,5]

ghci> [1,3..9]
[1,3,5,7,9]

ghci> [1] ++ [2,3]  -- 列表的连接
[1,2,3]

ghci> 1 : [2,3]  -- 元素和列表的连接,类似cons
[1,2,3]

ghci> head [1,2,3]   -- 返回列表的第一个元素
1

ghci> tail [1,2,3]   -- 返回除去第一个元素后的剩余列表
[2,3]

ghci> last [1,2,3]   -- 返回列表的最后一个元素
[3]

ghci> init [1,2,3]   -- 返回除去最后一个元素的剩余列表
[1,2]

ghci> reverse [1,2,3]
[3,2,1]

ghci> take 2 [1,2,3]  -- 返回列表的前n个元素组成的新列表
[1,2]

ghci> drop 1 [1,2,3]  -- 返回丢弃前n个元素后得到的新列表
[2,3]

ghci> null []
True

ghci> (1, "Hello")    -- 元组
(1, "Hello")

ghci> fst (1,"Hello")  -- 取元组的第一个元素
1

ghci> snd (1,"Hello")  -- 取元组的第二个元素
"Hello" 

1987年9月在美国俄勒冈州的波特兰,
举行了一次关于函数式编程语言和计算机体系结构的会议,FPCA'87。
会议看到了函数式编程社区的现状,
社区中已经出现了十几个非严格的(non-strict)语义的纯函数式编程语言,
它们全都表现力丰富,而且建立在语义学基础之上。

美高梅线上平台游戏 2

字符串

Haskell的字符串和C的非常相似,用单引号表示单个字符,双引号代表字符串,字符串实际就是单个字符的列表,但不需要像C中用''结尾

ghci> 'a'
'a'

ghci> "Hello World"
"Hello World"

ghci> ['H','e','l','l','o']
"Hello"

ghci> "" == []
True

ghci> 'a' : "bc"
"abc"

ghci> "a" ++ "bc"
"abc"

人们看到,没有一门公共语言妨碍了这些语言的广泛使用。
于是,会议达成共识,决定设计一门新的语言,用来更快的交流新想法,
这样可以保证基础更加牢固,也可以推动实际生产环境中的使用。
对于那些想学习函数式语言的人们,也方便了许多。
这门语言就是Haskell,以逻辑学家Haskell B. Curry命名。

 

查看表达式类型

在交互式界面下,我们有两种方法查看表达式的类型:

ghci> :set +t
ghci > 'a'
'a'
it :: Char    -- it是交互模式下存储运算结果的变量
ghci> :unset +t
ghci> 'a'
'a'

ghci> :type 'a'
'a' :: Char
ghci> :type 1 + 1
1 + 1 :: Num a => a    -- :type执行静态的类型推导,并不会显示运算结果2的类型

Haskell的设计初衷是满足以下几个约束条件:
(1)它必须便于教学,科研和使用,可以用于构建大型系统。
(2)它必须完全用形式化的方法来表示语法和语义。
(3)它必须是免费的。任何人可以实现它,传播它。
(4)它必须建立在共识的基础之上。
(5)它必须消除众多函数式语言中不必要的多样性。

本文转载自:

分数

ghci> :m +Data.Ratio      -- ':m'代表载入模块
ghci> :set +t
ghci> 1 % 2               -- 分数1/2
1 % 2
it :: Integral a => Ratio a

整数范围

Haskell中的整数是不限大小的,你可以写出下面的式子:

ghci> 313 ^ 15
27112218957718876716220410905036741257

和其他的语言一样,Haskell一直在演化。
到1997年年中,就已经更新了5个版本,Haskell 1.0-1.4。
在阿姆斯特丹的Haskell工作室(workshop),决定发布一个稳定的版本。
于是,1999年2月制订了名为“Haskell 98”的规范。
修复了少量Bug的“Revised Haskell 98”的规范于2002年发布。

自定义函数

在ghci中定义函数的语法和标准Haskell有所不同,我们在后者环境下定一个函数add,并加载到ghci环境中:

-- this is in myDrop.hs
myDrop n xs = if n <= 0 || null xs
              then xs
              else myDrop (n - 1) (tail xs)
-- back to ghci mode
ghci> :load myDrop.hs
ghci> myDrop 2 "cat"
"t"

2005年,Haskell出现了很多扩展,且以不同的形式实现了。
在社区力量的推动下,人们确定了一个规范制订的流程Haskell Prime,
力求把那些熟知的,广泛使用的特性加入到Haskell 98中,
目的是保持语言的稳定性,同时也能反映最新的研究成果。

副作用

避免函数的副作用有很多好处,在Haskell中,定义的函数默认都是无副作用的(纯函数),有副作用的函数在Haskell中类型会带有IO标签:

ghci> :type readFile
readFile :: FilePath -> IO String

纯度减轻了理解一个函数所需的工作量。一个纯函数的行为并不取决于全局变量、数据库的内容或者网络连接状态。纯代码(pure code)从一开始就是模块化的:每个函数都是自包容的,并且都带有定义良好的接口。
将纯函数作为默认的另一个不太明显的好处是,它使得与不纯代码之间的交互变得简单。一种常见的 Haskell 风格就是,将带有副作用的代码和不带副作用的代码分开处理。在这种情况下,不纯函数需要尽可能地简单,而复杂的任务则交给纯函数去做。
软件的大部分风险,都来自于与外部世界进行交互:它需要程序去应付错误的、不完整的数据,并且处理恶意的攻击,诸如此类。Haskell 的类型系统明确地告诉我们,哪一部分的代码带有副作用,让我们可以对这部分代码添加适当的保护措施。
通过这种将不纯函数隔离、并尽可能简单化的编程风格,程序的漏洞将变得非常少。

对语言本身进行一次大量的改动是个艰巨的任务,
最好能够以小步快跑的方式来推动语言的演化,
每次修订最好只包括少量的一些特性,
目前Haskell 2010是第一个修订版。

变量

在Haskell中,一个变量和一个值建立绑定之后,这个变量的值就不可以再被修改了,举个例子,下面的代码是无法通过编译的:

-- file: ch02/Assign.hs
x = 10
x = 11

命令式语言中的变量是和一个内存地址建立了绑定,但地址里写的内容是可以反复修改的,所以在命令式语言中不同时刻读取同一变量的值可能会得到不同的结果。在Haskell中,变量是和值建立的绑定,一个变量被绑定后,我们总能把变量替换成绑定的值。

Haskell 2010 committee已经解散了,
最近成立的委员会是Haskell Prime 2020 committee,
目标是产出Haskell 2020语言规范。

惰性求值

Haskell中用于追踪未求值表达式的记录被称为块。编译器通过创建块来延迟表达式的求值,直到这个表达式的值真正被需要为止。如果某个表达式的值不被需要,那么从始至终,这个表达式都不会被求值。在Haskell中可以定义无限长的数组,并可以对其进行一些操作:

-- mycons.hs
mycons n = n : mycons (n + 1)
l = mycons 0       -- l是自然数集合

-- ghci
ghci> :load mycons.hs
ghci> take 3 l
[0,1,2]
ghci> (!!) l 0    -- !!是根据下标取列表元素的操作,从0开始
0
ghci> takeWhile(x->x<3) l
[0,1,2]

Haskell还自带了一个repeat::a->[a]函数,他接受一个参数x,返回一个无限个x组成的列表。


类型系统

Haskell的类型系统基于简洁而强大的 System F,这里我们不深究其实现,只列出Haskell类型系统的三个特性:

  • 强类型:强类型语言不会做隐式的类型转换。举个例子,如果将一个整数值作为参数传给了一个接受浮点数的函数,C 编译器会自动且静默(silently)地将参数从整数类型转换为浮点类型,而 Haskell 编译器则会引发一个编译错误。
  • 静态类型:静态类型的语言会在编译阶段求出所有变量和表达式的类型,并拒绝执行任何类型错误的程序。同时,Haskell还提供了 typeclass 机制让程序员实现一些动态类型语言的功能。
  • 自动推导:如果没有自动推导,那么一门静态语言就要求程序员事无巨细地显示声明所有变量的类型以及类型之间的关系,就像Java采用的norminal type system。和很多函数式语言一样,Haskell可以几乎自动推导出所有表达式的类型(有时需要程序员提供一些必要的提示)。这使得程序员在编码时几乎不需要写任何的类型信息(写出来当然也是可以的),但同时编译时期也有强大的类型检查保证Haskell代码的类型安全。

参考:
haskell2010
Language and library specification
Haskell Prime

多态

Haskell中列表中的值可以是任意类型,所以我们可以称列表为类型多态(polymorphic)的。任何列表相关的操作函数应当也是多态的,看一个例子:

ghci> :type last
ghci> last :: [a] -> a

这里last的类型中包含了一个类型变量a,在不同情况下它会具化成不同的类型,当last函数应用于一个字符串的时候,其类型就是[Char]->Char,而应用于一个整数数组时,last的类型就是[Integer]->Integer

下一篇:没有了

更多新闻推荐

Copyright © 2015-2019 http://www.77zhth.net. 美高梅官方网站66159有限公司 版权所有