Haskell

历史

1985年，Miranda发行后，惰性函数式语言的关注度增长。到1987年前，出现了十多种非限定性、纯函数式语言。其中，Miranda使用的最为广泛，但还没有出现在公共领域。在俄勒冈波特兰的函数式编程语言与计算机结构大会（FPCA '87）上，参加者一致同意形成一个委员会来为这样的语言定义一种开放性标准。该委员会旨在集成已有函数式语言，作为将来的函数式语言设计研究工作的基础。

Haskell 1.0至1.4

1990年定义了Haskell的第一个版本（“Haskell 1.0”）。委员会形成了一系列的语言定义（1.0，1.1，1.2，1.3，1.4）。

Haskell 98

1997年底，该系列形成了Haskell 98，旨在定义一个稳定、最小化、可移植的语言版本以及相应的标准库，以用于教学和作为将来扩展的基础。委员会明确欢迎创建各种增加或集成实验性特性的Haskell 98的扩展和变种。
1999年2月，Haskell 98语言标准公布，名为《The Haskell 98 Report》。2003年1月，《Haskell 98 Language and Libraries: The Revised Report》公布。接着，Glasgow Haskell Compiler (GHC)实现了当时的事实标准，Haskell快速发展。

Haskell Prime

2006年早期，开始了定义Haskell 98标准后续的进程，非正式命名为Haskell Prime。这是个修订语言定义的不断增补的过程，每年产生一个新的修订版。第一个修订版于2009年11月完成、2010年7月发布，称作Haskell 2010。

Haskell 2010

Haskell 2010加入了外部函数接口（Foreign Function Interface，FFI）允许绑定到其它编程语言，修正了一些语法问题（在正式语法中的改动）并废除了称为“n加k模式”（换言之，不再允许形如fact (n+1) = (n+1) * fact n的定义）。引入了语言级编译选项语法扩展（Language-Pragma-Syntax-Extension），使得在Haskell源代码中可以明确要求一些扩展功能。Haskell 2010引入的这些扩展的名字是DoAndIfThenElse、HierarchicalModules、EmptyDataDeclarations、FixityResolution、ForeignFunctionInterface、LineCommentSyntax、PatternGuards、RelaxedDependencyAnalysis、LanguagePragma、NoNPlusKPatterns。

特性

Haskell是现有的一门开放的、已发布标准的，且有多种实现的语言。支持惰性求值、模式匹配、列表解析、类型类和类型多态。它是一门纯函数编程语言，这意味着大体上，Haskell中的函数没有副作用。Haskell用特定的类型来表达副作用，该类型与函数类型相互独立。纯函数可以操作并返回可执行的副作用的类型，但不能够执行它们，只有用于表达副作用的类型才能执行这些副作用，Haskell以此表达其它语言中的非纯函数。
Haskell拥有一个基于Hindley-Milner类型推论的静态、强类型系统。Haskell在此领域的主要创新就是加入了类型类（type class），原本设想作为重载的主要方式，在之后发现了更多用途。
Haskell的主要实现GHC是个解释器，也是个原生代码编译器。它可以在大多数平台运行，GHC在并发和并行上具有高性能的实现能力，也有丰富的类型系统，如广义代数数据类型和类型族（Type Families）。
单子是一个抽象类型，可以表达不同种类的计算，包括异常处理、非确定性、语法分析以及软件事务内存，其中一个应用是用于表达副作用的类型。单子定义为普通的数据类型，同时Haskell也为其提供了几种语法糖。
Haskell有一个活跃的社区，在线上包仓库Hackage上有丰富的第三方开源库或工具。

数据类型

Haskell是强类型语言。
Char的字面值用单引号围起；
字符串即[Char]类型，其字面值用双引号括起来。
Int通常为32位整型Integer是无界整型Float 表示单精度的浮点数Double 表示双精度的浮点数Bool 只有两种值：True 和 False。

控制结构

if then else是分段函数定义时的语法糖。与C语言不同，要求必须有else部分。类似于C语言分支语句的情形，叫做pattern matching，例子如下：
 1 pts :: Int -> Int 2 pts 1 = 10 3 pts 2 = 6 4 pts x 5     | x <= 6    = 7 - x 6     | otherwise = 0 7  8 (||) :: Bool -> Bool -> Bool  -- 或操作的类型与定义 9 True  || _ = True             -- 第二个参数是任何值都匹配。 10 False || y = y

lambda函数

lambda 就是匿名函数。写法是：一个 \ (因为它看起来像是希腊字母λ)，后面是用空格分隔的参数，-> 后面是函数体。通常用括号将括起lambda函数，否则它会占据整个右边部分。
例如：(\a b -> (a * 30 + 3) / b)
可以在lambda 中使用模式匹配，但无法为一个参数设置多个模式，如 [] 和 (x:xs)并用。
使用 lambda 可以更明确地表现出值是个函数，可以用来传递给其他函数作参数。

高阶函数

Haskell的所有函数实际上是单参数函数。多参数函数的写法实际上是Curry化的语法糖。即 func a b等价于(func a) b
point free style (也称作pointless style) 的函数，即通过柯里化(Currying)省略掉单参数。例如：
sum' :: (Num a) => [a] -> a     
sum' xs = foldl (+) 0 xs   --等号的两端都有个xs。 
sum'   = foldl (+) 0     --柯里化(Currying)，可以省掉两端的xs。
中缀运算符可以加括号变为单参数函数。如 (*3) 5 的值为15。 但(-5)表示负值，所以单参数函数需要写为(subtract 5)。
中缀运算符$，可用于改变函数的调用次序，使其右边的表达式先计算出来。这可以减少一对括号使用。例如 f (g (z x)) 与 f $ g $ z x 等价。其定义是：
($) :: (a -> b) -> a -> b  
f $ x = f x  
$ 还可以将数据作为函数使用。例如：
map ($ 3) [(4+),(10*),(^2),sqrt]
中缀运算符. 用于函数的复合，其定义是：
(.) :: (b -> c) -> (a -> b) -> a -> c  
f . g = \x -> f (g x)

异常处理

提供了处理异常的函数///.  
 1 import Prelude hiding(catch) 2 import Control.Exception 3 instance Exception Int 4 instance Exception Double 5 main = do 6   catch 7     (catch 8       (throw (42::Int)) 9       (\e-> print (0,e::Double)))10     (\e-> print (1,e::Int))
输出结果
(1,42)
类似于C++
 1 #include <iostream> 2 using namespace std; 3 int main() { 4     try { 5         throw (int)42; 6     } catch (double e) { 7         cout << "(0," << e << ")" << endl; 8     } catch (int e) { 9         cout << "(1," << e << ")" << endl;10     }11 }
另外一个例子：
1 do {2   -- Statements in which errors might be thrown3 } `catch` \ex -> do {4   -- Statements that execute in the event of an exception, with 'ex' bound to the exception5 }
如果仅有一个错误条件， 类足够用了，确省是Haskell的  class. 更复杂的出错处理用 或 monads, 类似功能可用。

Haskell的函数结构

如下是Haskell语言的"Hello world"，注意其中除最后一行外皆可省略。
1 module Main where2 3 main :: IO ()4 main = putStrLn "Hello, World!"
如下是阶乘函数的Haskell实现：
1 fac :: Int -> Int2 fac 0 = 13 fac n = n * fac (n - 1)
它将阶乘描述成有一个基本终止情形的递归函数。这跟数学定义中对阶乘的描述很相似。事实上，Haskell中很多的代码的语法与功能都和数学一致。
上面的递归函数的第一行是可选的，它描述了这个函数的类型（types）。它可以读作函数fac的类型为整数至整数（function fac has a int-to-int type）。这就是说，它以一个整型为参数，并且返回另一个整型。
第二行依赖的模式匹配，是Haskell程序中一个重要的部分。注意函数的参数是用空格分隔而不是在括号中。当函数的参数是0时，它会返回整型1。对于其他的情况则尝试第三行。这是一个递归，它会一直执行只到满足基本的情形。负参数会导致无限递归，一个guard保证第三行不会执行负参数。
"Prelude"是一个类似C中标准库的小函数集合。使用Prelude，并用无指定参数的写法，它可以改成：
1 fac = product . enumFromTo 1
上面的定义接近于数学中的定义：f = g o h（参见复合函数），这并不是一个对变量赋值的语句。

Haskell的高阶函数

Haskell中可以定义高阶函数（Higher-order Function），既将函数作为一个参数来使用，也可以将函数作为结果输出，例如：
1 f :: (Int -> Int) ->(Int -> Int)2 f g = \x -> g x + 5
这里f就是一个高阶函数，它取一个从Int到Int的函数g作为参数，输出一个从Int到Int的函数。高阶函数的使用在一些情况下将极大的简化代码。