↓ Skip to main content
  1. Posts/

基础 Haskell 学习笔记

·1463 words·3 mins
Note: This article is available in Chinese only. 本文暂无英文版本。 View original

出于对函数式编程语言这一技能点的缺失…以及退役之后闲得蛋疼

打算浅尝辄止地学一下 haskell

这篇笔记不会写成文档那样详尽..毕竟函数式编程语言也是编程语言,有很多和其他编程语言(命令式?)相似的地方。

所以只会写一些简单的语法+让我感到惊讶的地方orz

总体的感觉…在里面看到了些 Python 和 Pascal 的影子 orz,比如子界,已经好久没见到了

变量
#

  • 命令式语言中,变量用来跟踪状态(keeping track of state)。
  • Haskell 中,变量保存了一个值,然后再也不可以修改它了。
  • 变量不仅可以保存像 3.14 这样的数值,还可以保存任何 Haskell 表达式

函数
#

  • 函数中的函数
1Prelude> let areaRect l w = l * w
2Prelude> let areaSquare s = areaRect s s
3Prelude> areaSquare 5
425

列表
#

  • 创建列表/添加元素
 1Prelude> let numbers = [1,2,3,4]
 2Prelude> numbers
 3[1,2,3,4]
 4Prelude> 0:numbers
 5[0,1,2,3,4]
 6Prelude> 1:0:numbers
 7[1,0,1,2,3,4]
 8Prelude> 2:1:0:numbers
 9[2,1,0,1,2,3,4]
10Prelude> 5:4:3:2:1:0:numbers
11[5,4,3,2,1,0,1,2,3,4]
  • 事实上所有的列表都是在一个空的列表([])的基础上通过附加数据创建的。逗号与方括号的记法实际上是一种语法糖般的令人愉快的形式。换句话说,[1,2,3,4,5] 精确地等同于 1:2:3:4:5:[]
  • 列表中的元素必须有相同的类型
  • 列表的嵌套(二维以及高维度)
  • 列表大概可以类比数组或者 Python 中的 list
  • 将两个 List 合并是很常见的操作,这可以通过 ++ 运算符实现。运算时会遍历左边的 list,因此用 : 运算符往一个 List 前端插入元素会是更好的选择。
  • 若是要按照索引取得 List 中的元素,可以使用 !! 运算符,索引的下标是从 0 开始的。
1ghci> "Steve Buscemi" !! 6
2'B'
3ghci> [9.4,33.2,96.2,11.2,23.25] !! 1
433.2
Haskell 列表分割示意图(head/tail/init/last)

元组
#

  • 类似 C++ 中的 pair,只不过不一定是 2 个元素
  • 事先知道你要储存多少个值为一组元组(例如数据是二维坐标)
  • 元组对其中值的类型没有同一性的要求
  • 若元组的长度为 n 则称其为 n-tuple。特殊地如果元组的长度为 2 则称其为 ‘pairs’(对),如果元组的长度为 3 则称其为 ’triples’。
 1Prelude> fst (2, 5)
 22
 3Prelude> fst (True, "boo")
 4True
 5Prelude> snd (5, "Hello")
 6"Hello"
 7
 8Prelude> let first (x, y) = x
 9Prelude> first (3, True)
103
  • 列表和元组可以任意方式嵌套

在源文件里写代码(和在解释器里的区别)
#

  • 定义变量没有 let
  • 不能定义同一个量两次
  • 顺序不重要:你声明变量的顺序不重要。例如,下面的代码片段可以得到完全同样的结果:
y = x * 2
x = 3
x = 3
y = x * 2
  • 变量不可改变的事实意味着我们随意选择以任何顺序写代码(但是这也是我们不能声明一个量一次以上的原因–否则那将是模棱两可的)。

条件表达式
#

  • if/else/then
1mySignum x =
2    if x < 0 then
3        -1
4    else if x > 0 then
5        1
6    else
7        0
  • case语句
1f x =
2    case x of
3      0 -> 1
4      1 -> 5
5      2 -> 2
6      _ -> (-1)

_ 为通配符,表示任何值都可以符合这个条件。

缩进
#

  • 上面的代码中缩进是非常重要的。
  • Haskell 使用一个叫“layout”的布局系统对程序的代码进行维护(Python 语言也使用一个相似的系统)。这个布局系统允许我们可以不需要像 C、Java 语言那样加分号跟花括号来对代码段进行分割。

为不同参数定义一个函数(分段函数)
#

1f 0 = 1
2f 1 = 5
3f 2 = 2
4f _ = -1
  • 该定义与顺序有关,如果把 f _ = -1 放在最前面,那么无论输入何值,都会得到 -1

函数合成
#

  • 函数合成就是把一个函数的结果作为另一个函数的参数。
  • 函数的这种合成方式普遍存在于其它编程语言中。在 Haskell 中有另外一种更数学化的表达方法:(.) 点函数。点函数源于数学中的 \( \circ \) 符号。
  • 在数学里我们用表达式 \( f\circ g \) 表达 “f following g.";在 Haskell 中,代码 f . g 也表达同样的含义,其中 \( f\circ g \) 等同于 \( (f\circ g)(x)=f(g(x)) \)。

let 绑定(类似局部变量)
#

要求 \( x={\frac {-b\pm {\sqrt {b^{2}-4ac}}}{2a}} \)

 1roots a b c =
 2    ((-b + sqrt(b*b - 4*a*c)) / (2*a),
 3     (-b - sqrt(b*b - 4*a*c)) / (2*a))
 4
 5roots a b c =
 6    let disc = sqrt (b*b - 4*a*c)
 7    in  ((-b + disc) / (2*a),
 8         (-b - disc) / (2*a))
 9
10roots a b c =
11    let disc = sqrt (b*b - 4*a*c)
12        twice_a = 2*a
13    in  ((-b + disc) / twice_a,
14         (-b - disc) / twice_a)

参考资料:Wikibooks_Haskell

Haskell 趣学指南

Related

MPI 学习笔记

·592 words·2 mins
参考资料: 消息传递接口(MPI)维基百科 MPI_TUTORIAL MPI 在大规模机器学习领域的前景如何? 因为要和平台组对接工作以及写我们自己的BN同步…所以来了解一下MPI相关…感谢平台组@gyz 菊苣提供指导。