说在前面
最近,Java写恶心了,计划重新捡起丢在一边很久的Scala,但是,Scala是个大怪物,几年前刚接触Scala的时候,认认真真地读过一遍原版《Programming in Scala : A Comprehensive Step-by-step Guide》,但是完全迷失在一堆难于理解的概念中。回头细想,本质上还是缺乏函数式编程的功底。为了更好地理解函数式编程的核心理念,我就用Haskell这门纯粹的函数式语言作为起点,开启我的重拾Scala之路。
Install Haskell Environment in Mac Step By Step
| 1 | % brew install ghc cabal-install | 
| 1 | % ghci | 
Basic Concepts
定义函数
| 1 | Prelude> let double x = x * 2 | 
定义模块
| 1 | ./double.hs | 
| 1 | Prelude> :load double.hs | 
递归
递归的不同实现 -> 阶乘问题
一行递归
| 1 | Prelude> let fact x = if x==0 then 1 else fact (x - 1) * x | 
模式匹配
| 1 | ./factorial.hs | 
哨兵表达式
| 1 | ./fact_with_guard.hs | 
高效地处理递归,元祖和列表 -> Example: 斐波那契序列问题
不够高效的实现:模式匹配
| 1 | ./fib.hs | 
高效实现:利用元组,转换为尾递归
| 1 | ./fib_tuple.hs | 
利用函数的组合
| 1 | ./fib_pair.hs | 
高阶函数
匿名函数(lambda)
| 1 | Prelude> (\x -> x ++ "World!") "Hello " | 
map
| 1 | -- map + lamda | 
filter
| 1 | *Main> filter odd [1, 2, 3, 4, 5] | 
flodl, foldr
| 1 | Prelude> foldl (\x carryOver -> carryOver + x) 0 [1 .. 10] — fold from left to right | 
foldl的一种简化表达: fold1
| 1 | Prelude> foldl1 (+) [1 .. 10] | 
Advanced Concepts
偏应用函数:将多参数的函数拆分为多个只有一个参数的函数
| 1 | -- 发现偏应用 | 
| 1 | -- 偏应用:绑定函数的一部分参数 | 
偏应用函数的运算过程称为柯里化
- prod 2 4 实际上计算(prod 2) 4
- 几乎每个Haskell的多参数函数都是柯里化的
惰性求值: 仅仅完成一部分必要的计算
| 1 | -- 可以构造无穷列表 | 
类型系统
原生类型
| 1 | Prelude> :set +t | 
自定义类型(利用data关键字定义)
| 1 | ./cards-with-show.hs | 
注:deriving用于函数的继承,代码段中继承了show函数用于在控制台中显示自定义数据类型Suit和Rank
| 1 | Prelude> :load cards-with-show.hs | 
类型模板 -> 实现函数的多态以及数据类型的多态
| 1 | ./type_template.hs | 
自定义类型模板
| 1 | ./userdefine_type_template.hs | 
| 1 | *Main> :load userdefine_type_template.hs | 
注:Triplet: 类型构造器,Trio: 数据构造器
自定义递归类型
| 1 | ./tree_depth.hs | 
| 1 | *Main> :load tree_depth.hs | 
类
- 为了便于实现函数的继承、重载、多态
- 不同于面向对象中的Class:对象是类型,不涉及数据
| 1 | -- 内置的Eq类,实现了相等判断 | 

Monad
- 本质上,一个Monad是一个函数组合
- 以特定属性的方式组合函数替代原来的嵌套调用,
- 一个monad = 类型容器 + return函数 + >>==bind函数
用途:
- 可以用于模拟程序的状态,从而实现用纯函数式较难实现的事情,比如IO
- 基于moand实现的do语法可以支持命令式风格的编程
- Maybe monad可以用来进行错误处理
Example 1:醉汉问题
嵌套方式实现
| 1 | ./drunken-pirate-without-monad.hs | 
利用Monad实现
| 1 | ./drunken-pirate-monad.hs | 
| 1 | *Main> treasureMap (Position 0) | 
Example 2: 利用do实现I/O monad
| 1 | ./io-monad.hs | 
| 1 | Prelude> :load io-monad.hs | 
Reference

订阅我的微信公众号,您将即时收到新博客提醒!