programming language 学习笔记 Part A

编程语言 :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开头
  • ifthenelse
  • 等于: = ; 不等于: <>
  • 负数: ~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
        programming language 学习笔记 Part A_第1张图片
    • 操作(提取):

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参数
  • 类型推断

    • 无需指明类型,编译器在编译期间自动识别
    • 静态类型语言才有
    • 所以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

programming language 学习笔记 Part A_第2张图片

  • 通配符 (_) 匹配任意值
  • exception

    • 建立exception
      • MyUndesirableCondition
      • MyUndesirableCondition int * int
    • 使用
      • raise MyUndesirableCondition
      • handle MyUndesirableCondition => e2
    • 实际上是模式匹配
  • 尾递归

    • 递归到最后一步后无需任何操作,直接返回值
    • 不用每次递归都创建一个新的栈,而是覆盖原有的
    • 需要一个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
    • https://stackoverflow.com/questions/1047454/what-is-lexical-scope
    • https://www.zhihu.com/question/20032419
    • https://www.cnblogs.com/lienhua34/archive/2012/03/10/2388872.html
  • 在FP中,函数是“一等公民”,可以传入函数,作为返回值。。。
    - 函数相当于值,任何可以使用值得场合都可以使用函数
    - 函数可出现在list和tuple中
  • 函数是binding,不是expression
    programming language 学习笔记 Part A_第3张图片
  • 匿名函数
    • 例: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
  • 静态作用域
    • 绝大多数语言是静态作用域的
    • 不要与动态语言静态语言搞混
      • 这个是以是否在编译期间确定变量类型而区分的
    • use environment where function is defined

programming language 学习笔记 Part A_第4张图片

programming language 学习笔记 Part A_第5张图片

  • 避免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化
    programming language 学习笔记 Part A_第6张图片

这里写图片描述
- 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,报错等
  • 相互递归
    • 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

你可能感兴趣的:(编程语言)