【Haskell】
Haskell（ˈhæskəl）是一种标准化的，通用的纯函数式编程语言，有惰性求值和强静态类型。它的命名源自美国逻辑学家哈斯凯尔·加里，他在数理逻辑方面上的工作使得函数式编程语言有了广泛的基础。在Haskell中，“函数是头等物件”。作为一门函数程式语言，主要控制结构是函数。Haskell语言是1990年在编程语言Miranda的基础上标准化的，并且以λ演算为基础发展而来。这也是为什么Haskell语言以希腊字母「λ」（Lambda）作为自己的标志。Haskell具有“证明即程序、命题为类型”的特征。
==历史==
1985年，Miranda发行后，惰性函数式语言的关注度增长。到1987年前，出现了十多种非限定性、纯函数式语言。其中，Miranda使用的最为广泛，但还没有出现在公共领域。在俄勒冈波特兰的函数式编程语言与计算机结构大会（FPCA '87）上，参加者一致同意形成一个委员会来为这样的语言定义一种开放性标准。该委员会旨在整合已有函数式语言，作为将来的函数式语言设计研究工作的基础。
===Haskell 1.0至1.4===
能够确使类型安全的运算符重载的类型类，是由Philip Wadler和Stephen Blott最初为Standard ML提议的，但首先在Haskell中于1987年至版本1.0期间实现。
1990年定义了Haskell的第一个版本（“Haskell 1.0”）。委员会形成了一系列的语言定义（1.0，1.1，1.2，1.3，1.4）。
在GHC 7.10的Haskell prelude中的类型类层级。包括了Foldable和Traversable（相应的改变了一些函数的类型签名），和作为Functor与Monad中介的Applicative，它们出自Haskell 2010标准。
===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》公布。接着，格拉斯哥Haskell编译器实现了当时的事实标准，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在此领域的主要创新就是加入了类型类，原本设想作为重载的主要方式，在之后发现了更多用途。
Haskell的主要实现GHC是个解释器，也是个原生代码编译器。它可以在大多数平台运行，GHC在并发和并行上具有高性能的实现能力，也有丰富的类型系统，如广义代数数据类型和类型族（Type Families）。
单子是一个抽象类型，可以表达不同种类的计算，包括异常处理、非确定性、语法分析以及软件事务内存，其中一个应用是用于表达副作用的类型。单子定义为普通的数据类型，同时Haskell也为其提供了几种语法糖。
Haskell有一个活跃的社区，在线上包仓库Hackage上有丰富的第三方开源库或工具。
== 语法 ==
===数据类型===
Haskell是强类型语言。Char的字面值用单引号围起；字符串即Char类型，其字面值用双引号括起来。Int通常为32位整型；Integer是无界整型；Float 表示单精度的浮点数；Double 表示双精度的浮点数；Bool 只有两种值：True 和 False。
====List====
使用 与逗号分隔符，定义一个list的实例。其元素必须具有相同类型。字符串是list的特例。用:把元素与list、其他元素连接（cons）起来。:是右结合的运算符。1,2,3 实际上是 1:2:3: 的语法糖。两个 List 合并通过 ++ 运算子实现。按照索引取得 List 中的元素，可以使用
运算子，索引的下标为 0。List 中的 List 可以是不同长度，但必须得是相同的型别。'K'..'Z'这样的Range方法快捷定义一个List。2,4..20用法给出了Range的第一、第二、最后一个元素。使用 > 和 >= 可以比较 List 的大小。它会先比较第一个元素，若它们的值相等，则比较下一个，以此类推。List常用的函数:
* head 返回一个 List 的头部，也就是 List 的首个元素。
* tail 返回一个 List 的尾部，也就是 List 除去头部之后的部分。
* last 返回一个 List 的最后一个元素。
* init 返回一个 List 除去最后一个元素的部分。
* length 返回一个 List 的长度。
* null 检查一个 List 是否为空。如果是，则返回 True，否则返回 False。
* reverse 将一个 List 反转
* take 返回一个 List 的前几个元素。例如take 24 13,26..取前24个13的倍数
* drop 删除一个 List 中的前几个元素
* maximum 返回一个 List 中最大的元素。
* minimun 返回最小的元素。
* sum 返回一个 List 中所有元素的和。
* product 返回一个 List 中所有元素的积。
* elem 判断一个元素是否在包含于一个 List，通常以中缀函数的形式调用
* replicate 得到包含相同元素的 List 。例如：replicate 3 10，得 10,10,10。
* repeat 产生一个元素的无限重复的List
* cycle 接受一个 List 做参数并返回一个无限 List
list comprehension是指基于一个List，按照规则产生一个新List，例如： x = 12
====Tuple====
使用( )与逗号分隔符，定义一个tuple的实例。其元素可以使不同类型，但个数是固定的。
Tuple的类型取决于其中项的数目与其各自元素的类型。单元素的 Tuple 被禁止。
*fst 返回一个序对的首项。
*snd 返回序对的尾项
*zip 取两个 List作为参数，然后将它们依次配对，形成一组序对的 List。
=== 运算符===
基本类似于C语言。但使用not表示逻辑非。
+  -  *  /  ^    -- 加、减、乘、除、指数
mod              -- 取余数
$                -- 也是表示函数作用的, 但它的优先级最低, 而且作用次序是从右向左的
++               -- 两个List的连接
.                 -- 函数的复合
&&
==  /=     -- 与、或、等于、不等于
=        -- 小于等于、大于等于、小于、大于
: //  =  @        -- 一个元素连接List、
->               -- 函数类型描述，运算符左边为参数类型，右边为结果类型。为右结合。例如：addThree :: Int -> Int -> Int -> Int
=>               -- 运算符的左边表示一个类型变量（通常为单个小写字母）属于一个类型类（Typeclass），相当于C++语言的模板参数类型
..               -- List的Range限定
::               -- 函数/表达式的类型特征，左侧为函数/表达式，右侧为类型
result
pattern -> result
pattern -> result
...
=== 控制结构 ===
if then else是分段函数定义时的语法糖。与C语言不同，要求必须有else部分。类似于C语言分支语句的情形，叫做pattern matching，例子如下：
pts :: Int -> Int
pts 1 = 10
pts 2 = 6
pts x
x  Bool -> Bool  -- 或操作的类型与定义
True
_ = True             -- 第二个参数是任何值都匹配。
False
y = y
=== 函数 ===
* 函数调用有最高运算顺序，例如succ 9*10表示(succ 9)*10。
* 函数的调用使用空格符而不是括号。
* 函数的复合调用是左结合。
* 首字母大写的函数是不允许的。
* 两个参数的函数的调用可以写成中缀形式：param1 `funcName` param2。
* 运算符可以用括号围起来，作为前缀形式：(+) 2 3 的结果为5。
* 在 ghci 下，我们可以使用 let 关键字来定义一个常量。在 ghci 下执行 let a=1 与在脚本中编写 a=1 是等价的。
--funcName arguments = expression  --定义函数的一般形式
area r = pi * r ^ 2 -- 定义了一个函数
area 101 -- 调用了函数
f1 f2 3.14 -- 函数调用是左结合，等效于(f1 f2) 3.14
--模式匹配方式定义
factorial :: (Integral a) => a -> a
factorial 0 = 1
factorial n = n * factorial (n - 1)
--as模式，是将一个名字和 @ 置于模式前，可以在按模式分割参数值时仍保留对其整体的引用。如nameGlobal@(x:y:ys)，nameGlobal会匹配出与 x:y:ys 对应的东西。as模式在较大的模式中保留对整体的引用，从而减少重复性的工作。
heron a b c = sqrt (s * (s - a) * (s - b) * (s - c))
where                     -- where在表达式中局部绑定了名字s与一个值。也可以在表达式之前用let ... in语法
s = (a + b + c) / 2
absolute x                 -- 绝对值函数，使用了分段函数语法糖（称作Guards）
x  a -> a -> String
bmiTell weight height
bmi  String -> String
initials firstname lastname = f ++ ". " ++ l ++ "."
where (f:_) = firstname
(l:_) = lastname
--where可以定义函数。在定义一个函数的时候也写几个辅助函数摆在 where 绑定中。 而每个辅助函数也可以透过 where 拥有各自的辅助函数。
calcBmis :: (RealFloat a) => (a, a) -> a
calcBmis xs = bmi w h | (w, h)  type2 -> type3 -- 其中，::表示类型特征(type signature)，->是右结合，这里等效于type1 -> (type2->type3)，给定一个type1的输入参数，返回一个函数(type2->type3)
f1 = (absolute .  area)   -- 函数复合运算符是 . (function composition operator)
多态类型(Polymorphic types)类似于C++的模板。例如，算术加法：
(+) :: (Num a) => a -> a -> a -- Num是typeclass。 =>表示signature restricts
===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)
===异常处理===
提供了处理异常的函数try、catch、finally/etc.
import Prelude hiding(catch)
import Control.Exception
instance Exception Int
instance Exception Double
main = do
catch
(catch
(throw (42::Int))
(\e-> print (0,e::Double)))
(\e-> print (1,e::Int))
输出结果
(1,42)
类似于 C++
#include
using namespace std;
int main() {
try {
throw (int)42;
} catch (double e) {
cout
另外一个例子：
do {
-- Statements in which errors might be thrown
} `catch` \ex -> do {
-- Statements that execute in the event of an exception, with 'ex' bound to the exception
}
如果仅有一个错误条件，Maybe 类足够用了，确省是Haskell的 Monad class. 更复杂的出错处理用Error 或ErrorT monads, 类似功能可用`catch`。
== 示例 ==
=== Haskell的函数结构 ===
如下是Haskell语言的"Hello world"，注意其中除最后一行外皆可省略。
module Main where
main :: IO ()
main = putStrLn "Hello, World!"
如下是阶乘函数的Haskell实现：
fac :: Int -> Int
fac 0 = 1
fac n = n * fac (n - 1)
它将阶乘描述成有一个基本终止情形的递归函数。这跟数学定义中对阶乘的描述很相似。事实上，Haskell中很多的代码的语法与功能都和数学一致。
上面的递归函数的第一行是可选的，它描述了这个函数的型态（types）。它可以读作函数fac的型态为整数至整数（function fac has a int-to-int type）。这就是说，它以一个整型为参数，并且返回另一个整型。
第二行依赖的模式匹配，是Haskell程序中一个重要的部分。注意函数的参数是用空格分隔而不是在括号中。当函数的参数是0时，它会返回整型1。对于其他的情况则尝试第三行。这是一个递归，它会一直执行只到满足基本的情形。负参数会导致无限递归，一个guard保证第三行不会执行负参数。
"Prelude"是一个类似C中标准库的小函数集合。使用Prelude，并用无指定参数的写法，它可以改成：
fac = product . enumFromTo 1
上面的定义接近于数学中的定义：f = g o h（参见复合函数），这并不是一个对变量赋值的语句。
=== Haskell的高阶函数 ===
Haskell中可以定义高阶函数（Higher-order Function），既将函数作为一个参数来使用，也可以将函数作为结果输出，例如：
f :: (Int -> Int) ->(Int -> Int)
f g = \x -> g x + 5
这里f就是一个高阶函数，它取一个从Int到Int的函数g作为参数，输出一个从Int到Int的函数。高阶函数的使用在一些情况下将极大的简化代码。
== Haskell的编译器 ==
*  Hugsdate=20060203013111
*  ghc (Glasgow Haskell Compiler)date=20060208085900
*  yhc (York Haskell Compiler)date=20060203214652
*  nhc98date=20060203001010
== 参考文献 ==
== 外部连结 ==
*   Haskell的官方主页date=20061011005609
*   HaskellWiki：Haskell社群主网站date=20060127230539
*   UNSW的Haskell教程date=20070717111830
*   Haskell笑话date=20140731081743
*   Haskell旧的讨论主题
*   Haskell vs. Ada vs. C++ vs. Awk vs. ......一个实验性的前卫语言（PostScript档案）
*   Haskell编程的变革date=20070101192126  -- 一个轻快的Haskell编程风格总缆
*   一个Haskell研究者的线上介绍
*   ePolyglot -- 将Haskell、Python与Eiffel结合的语言date=20070108044857
*   Haskell函式库date=20070208020342
=== 教学手册 ===
*  用Haskell写程式date=20070110212407 ，Graham Hutton撰写
*  另一个Haskell教学手册date=20090915035309  -- 由Hal Daume III所写的好手册，需要比官方教学手册少的先备知识
*  A Gentle Introduction to Haskell 98date=20061011005414 （较高阶的教学手册，有 PDFdate=20061012011607 档案）
*  Haskell Tutorial for C Programmers，Eric Etheridge撰写
*  在Haskell.org的教学手册列表date=20061011015031
*  Haskell编程典范date=20060830114516
*  Haskell趣学指南date=20120621064324
*  Haskell趣学指南date=20180821160610