编程语言 :ML
参考:https://www.cnblogs.com/whensean/p/6134063.html
http://www.cnblogs.com/ftae/p/8039291.html
WEEK2:
- 变量被赋值后不可再变(immutable)
- && is andalso ;|| is orelse; ! is not
- 语句以var 或者 fun开头
- if … then … else…
- 等于: = ; 不等于: <>
- 负数: ~value
- fun name (var: type,var :type) = expression
- let binding(var / fun) in expression
- 返回值是e的类型
- 可以在任何可以使用expression的地方使用
- 可以使用之前定义的变量
- list( type: t list)
- append: e1::e2
- 空list :[]
- null name :判断是否为空list,返回true or false
- hd name 得到 首元素;tl name 得到 尾list
- tuples(type: t1*t2*t3)
- 取出元素 : #1 name
- option(type : t option)
- SOME e :t->t option
- NONE :空option
- valOf e: t option -> t
- isSome: 判断是否为空
例子:
//输出x到y之间所有的数的list
fun append (x: int, y: int) =
if y - x <0
then []
else x::append(x+1,y)
//求最大值
fun max (x: int list)=
if null x
then NONE
else
let fun max_nonempty( x: int list) =
if null (tl x)
then hd x
else
let val tl_ans = max_nonempty(tl x)(*防止重复递归*)
in
if hd x > tl_ans
then hd x
else tl_ans
end
in
SOME(max_nonempty x)(*单个参数可不加括号*}
- immutable
- 函数式语言变量都是不可改变的
WEEK3
- records
- a = {name1:type1,name2:type2…}
- 取数:#name1 a
- tuple是一种特殊的records,及{1:type1,2:type2…}
datatype
datatype mytype = Call1 | Call2 of string | Call3 of int * int
- Call 是 constructor
- 不一定要有of
操作(提取):
case x of
Call1 => e1
| Call2(Str) => e2
| Call3(a,b) => e3
别名: type foo = int*bool
list, option 实质都是 datatype
- 例如 list的constructor是 SOME 和 NONE
-datatype 'a mylist = Cons of 'a * ('a mylist) | Empty
‘a , ‘b … 是泛型
- ‘’a 是非函数和浮点数类型的泛型
pattern matching
- 所有函数实际上只有一个参数,多参数实质是传入一个tuple,
- 无参数实际传入了内置的unit参数
- 所有函数实际上只有一个参数,多参数实质是传入一个tuple,
类型推断
- 无需指明类型,编译器在编译期间自动识别
- 静态类型语言才有
- 所以SML函数的参数不用说明类型
pattern matching 不仅可以匹配one of类型(用case of),还可以匹配each of类型(tuple,records等),此时使用case of有些累赘,故可以直接用val来匹配
fun full_name (r : {first:string,middle:string,last:string}) =
case r of
{first=x,middle=y,last=z} => x ^ " " ^ y ^ " " ^z
//等价于
fun full_name (r : {first:string,middle:string,last:string}) =
let val {first=x,middle=y,last=z} = r
in
x ^ " " ^ y ^ " " ^z
end
更进一步
fun f(t: int * int * int) =
case t of (x, y, z) => x + y + z;
//可以简写成
fun sum_triple (x,y,z) =
x + y + z
- function binding 实际上是pattern matching, 故单个参数不用加括号,并且可以省略参数类型,因为会自动根据等号后的数值匹配
- nested pattern
exception BadTriple
fun zip3 list_triple =
case list_triple of
([],[],[]) => [] //避免了大量的case of
| (hd1::tl1,hd2::tl2,hd3::tl3) => (hd1,hd2,hd3)::zip3(tl1,tl2,tl3)
| _ => raise BadTriple
fun unzip3 lst =
case lst of
[] => ([],[],[])
| (a,b,c)::tl => let val (l1,l2,l3) = unzip3 tl
in
(a::l1,b::l2,c::l3)
end
- 通配符 (_) 匹配任意值
exception
- 建立exception
- MyUndesirableCondition
- MyUndesirableCondition int * int
- 使用
- raise MyUndesirableCondition
- handle MyUndesirableCondition => e2
- 实际上是模式匹配
- 建立exception
尾递归
- 递归到最后一步后无需任何操作,直接返回值
- 不用每次递归都创建一个新的栈,而是覆盖原有的
- 需要一个accumulator,并在最后一步返回accumulator的值
fun rev2 lst =
let fun aux(lst,acc) =
case lst of
[] => acc //accumulator
| x::xs => aux(xs, x::acc)
in
aux(lst,[])
end
WEEK4
- lexical scope and dynamic scope
- 在FP中,函数是“一等公民”,可以传入函数,作为返回值。。。
- 函数相当于值,任何可以使用值得场合都可以使用函数
- 函数可出现在list和tuple中 - 函数是binding,不是expression
- 匿名函数
- 例:fn x => x+1
- 无法递归
//等价
fun increment x = x + 1
val increment = fn x => x+1
- maps and filters
- map(f,list)
- 对list中的每个值采用f函数
- filter(f, list)
- 返回list中f(x)为真的x
- map(f,list)
- 静态作用域
- 绝大多数语言是静态作用域的
- 不要与动态语言静态语言搞混
- 这个是以是否在编译期间确定变量类型而区分的
- use environment where function is defined
- 避免recomputation
- function body is evaluated every time the function is defined
- A variable binding evaluates its expression when the binding is evaluated, not every time the variable is used
//第一个函数中String.size在每一次递归时都计算了一次,而第二个则只计算一次
fun allShorterThan1 (xs,s) =
filter(fn x => String.size x < String.size s, xs)
fun allShorterThan2 (xs,s) =
let val i = String.size s
in filter(fn x => String.size x < i, xs) end
- fold
- takes an “initial answer” acc and uses f to “combine” acc and the rst element of the list, using this as the new “initial answer” for “folding” over the rest of the list.
fun fold f = fn acc => fn xs =>
case xs of
[] => acc
| x::xs' => fold f (f(acc,x)) xs'
- 复合函数
//等价
fun sqrt_of_abs i = (Math.sqrt o Real.fromInt o abs) i
val sqrt_of_abs = Math.sqrt o Real.fromInt o abs
fun sqrt_of_abs i = i |> abs |> Real.fromInt |> Math.sqrt
- currying化
- partial application
//等价
fun sum1 xs = fold (fn (x,y) => x+y) 0 xs
val sum2 = fold (fn (x,y) => x+y) 0
mutation
- FP一般是immutation
- 使用reference表示mutable类型
- 构造:
val x = ref 0
- 取值:
!x
- 修改:
x := (!x) + 7
- 构造:
callbacks
- The val _ = e idiom is common for executing an expression just for its side-effect
ADT
- 使用closure来实现抽象和封装
- interface是各项是函数的record
- 不能用type代替datatype
- 因为type无法递归
闭包
- 函数被氛围两个部分,一个是函数代码和参数,一个是所包含的当前环境中的自由变量
WEEK5:
- modules
- 相当于JAVA中的package或者C中的namespace
open MyModule
来直接引用
structure MyModule =
struct
bindings
end
- signatures
- 作用类似private关键字,又像接口,隐藏内部细节,用以抽象
type
foo
- means the type exists, but clients do not know its definition
- 用不同的structure实现同一个signature时,内部变量不可通用
signature SIGNAME =
sig
types-for-bindings
end
//实现接口
structure MyModule :> SIGNAME =
struct
bindings
end
- 函数相等
- 不是输入和输出一样函数就是相等的,要考虑side effect
- 例如print,报错等
- 不是输入和输出一样函数就是相等的,要考虑side effect
- 相互递归
- and关键词实现
datatype t1 = Foo of int | Bar of t2
and t2 = Baz of string | Quux of t1
fun no_zeros_or_empty_strings_t1 x =
case x of
Foo i => i <> 0
| Bar y => no_zeros_or_empty_strings_t2 y
and no_zeros_or_empty_strings_t2 x =
case x of
Baz s => size s > 0
| Quux y => no_zeros_or_empty_strings_t1 y