programming language, part A 学习笔记3

week3主要内容:

自定义类型、语法糖、case表达式、多态类型、巧妙嵌套、尾递归。
以下为示例代码。

(*syntactic sugar*)
val a_pair = (3+1, 4+2);
val a_record = {second = 6, first = 3+1};

(*this is a pair, why?*)
val another_pair = {2 = 5, 1 = 6};

val x = {3 = "hi", 1 = true};
val y = {3 = "hi", 1 = true, 2 = 5};
(*there is no such thing as tuple in ML, only records!*)
(*tuples are just syntactic sugar for records*)


(*datatype bindings*)
datatype mytype = Twoints of int*int
    |Str of string
    |Pizza
(*Twoints and Str are funs, Pizza is a value*)

val a = Str "hi"
val b = Str   (*string -> mytype *)
val c = Pizza
val d = Twoints(3,7)
val e = a;

(*datatype bindings using aspects:*)
(*1. check what val it is*)
(*2. extract the data*)

(*case expressions*)
(*mytype -> int*)
fun f(x:mytype) = 
    case x of 
        Pizza => 3
        |Str s => String.size s
        |Twoints(i1, i2) => i1+i2;

f Pizza;
f(Str "hi");
(*f("hi");*)   (*wrong, not the type expects*)
f(Twoints(3,6));
(*why this is better*)
(* funs must contain all type branches, or it will warn. you wont forget*)

(*useful datatypes*)
datatype id = StudentNum of int
    | Name of string*(string option)*string

(*expression trees*)
datatype exp = Constant of int
    |Negate of exp
    |Add of exp * exp
    |MUL of exp * exp
    ;

(*recurtion*)
fun eval(e:exp) = 
    case e of
        Constant i => i
        |Negate e2 => ~(eval e2)
        |Add(e1, e2) => (eval e1) + (eval e2)
        |MUL(e1, e2) => (eval e1) * (eval e2)
        ;
val  exam_exp:exp = Add(Constant(10+9), Negate(Constant 4));
val exam_ans:int = eval exam_exp;

(*type synnonyms*)
(*create another name for the same type*)
datatype suit = club|Diamond|Heart|Spade
datatype rank = Jack|Queen|King|Ace|Num of int
type card = suit*rank
fun is_Queen_of_Spades(c:card) = 
    #1 c = Spade andalso #2 c = Queen
fun is_Queen_of_Spades2(c:card) = 
    case c of 
        (Spade, Queen) => true
        | _ =>false

val c1 :card = (Diamond, Ace)
val c2 : suit*rank = (Heart, Ace)
val c3 = (Spade, Ace)

is_Queen_of_Spades c1;
is_Queen_of_Spades c2;
is_Queen_of_Spades c3;
is_Queen_of_Spades2 c1;
is_Queen_of_Spades2 c2;
is_Queen_of_Spades2 c3; 

(*another example*)
(*
datatype exp = Constant of int
    |Negate of exp
    |Add of exp * exp
    |MUL of exp * exp
*)
fun max_constant e = 
    case e of 
        Constant i => i 
        |Negate e2 => max_constant e2
        |Add(e1, e2) => if max_constant e1 > max_constant e2
            then max_constant e1
            else max_constant e2
        |MUL(e1, e2) => if max_constant e1 > max_constant e2
            then max_constant e1
            else max_constant e2
val  test_exp:exp = Add(Constant(10+9), Negate(Constant 4))
val nineteen = max_constant test_exp 
(*to be concise*)
fun max_constant2 e = 
    let fun max_of_two(e1,e2) = 
        let val m1 = max_constant e1
            val m2 = max_constant e2
        in 
            if m1 > m2
            then m1
            else m2
            (*or Int.max(m1, m2)*)
        end
    in 
        case e of 
            Constant i => i 
            |Negate e2 => max_constant e2
            |Add(e1, e2) => max_of_two(e1, e2)
            |MUL(e1, e2) => max_of_two(e1, e2)
    end
(*to be concise*)
fun max_constant3 e = 
    case e of 
        Constant i => i 
        |Negate e2 => max_constant e2
        |Add(e1, e2) => Int.max(max_constant e1, max_constant e2)
        |MUL(e1, e2) => Int.max(max_constant e1, max_constant e2)

(*list and option datatypes*)
datatype my_int_list = Empty
    | Cons of int*my_int_list
fun append_my_list(xs, ys) = 
    case xs of  
        Empty => ys
        |Cons(x, xs') => Cons(x, append_my_list(xs', ys))

fun inc_or_zero intr = 
    case intr of
        NONE => 0
        |SOME i => i+1

fun sum_list xs = 
    case xs of
        [] => 0
        | x::xs' => x +sum_list xs'

fun append (xs, ys) =
    case xs of
        [] => ys
        |x::xs' => x:: append(xs', ys)

(*polymophic datatypes*)(*多态*)
datatype 'a option = NONE | SOME of 'a
datatype 'a mylist = Empty |Cons of 'a *'a mylist
datatype ('a, 'b) tree = 
    Node of 'a * ('a, 'b) tree * ('a, 'b) tree
    |Leaf of 'b
(*one or more type var before datatype name*)

fun sum_tree tr = 
    case tr of
        Leaf i => i
        |Node(i, lft, rgt) => i+ sum_tree lft+ sum_tree rgt
fun sum_leaves tr = 
    case tr of
        Leaf i => 1
        |Node(i, lft, rgt) => sum_leaves lft + sum_leaves rgt

val tree_test = Node(3, Node(2, Leaf 1, Leaf 4), Leaf 7);
sum_tree tree_test;
sum_leaves tree_test;

(*eachof pattern matching*)
(*argments:实参*)
fun sum_triple triple =
    case triple of
        (x, y, z) =>x+y+z 
(*better style*)
fun sum_triple2 triple = 
    let val(x,y,z) = triple
    in
        x+y+z
    end
    ;
(*great style*)
fun sum_triple3(x,y,z) =x+y+z ;
sum_triple3(1,2,3)
(*So how can ML tell which im trying to do?*)
(*how does it know to pass in on triple and pattern match against it,
instead of passing in three arguments?*)

(*ans: In ML, every function takes and returns exactly one argument*)
fun rotate_left(x,y,z) = (y,z,x);
rotate_left(1,2,3);
fun rotate_right(x,y,z) = rotate_left(rotate_left(x,y,z));
rotate_right(1,2,3);

(*type inference*)
fun sumtriple1(x,y,z) = x+y+z;
fun sumtriple2(triple: int*int*int) = #1 triple + #2 triple + #3 triple;

(*get int*'a*int -> int , 'a can be anytype *)
(*called unexpected polymorphism*)
fun partialsum(x,y,z) = x+z;

(*polymophic types and equality types*)
(* fun append (xs, ys) =
    case xs of
        [] => ys
        |x::xs' => x:: append(xs', ys) *)
(*it has to be the esame type*)
(*val not_ok = append([1,2], ["programming", "languages"]);*)

(*two quotes before a type: equality types*)
(* fn: ''a *''a -> string *)
fun same_thing(x, y) =
    if x = y 
    then "yes"
    else "no"
(*same_thing(1,"ji");*)

(*nested patterns*)(*嵌套*)

(*don't do this*)
exception ListLengthMismatch
(*'a lsit *'b list * 'c list -> ('a*'b*'c) list*)
fun old_zip(l1, l2, l3) =
    if null l1 andalso null l2 andalso null l3 
    then []
    else if null l1 orelse null l2 orelse null l3
    then raise ListLengthMismatch
    else (hd l1, hd l2, hd l3) :: old_zip(tl l1, tl l2, tl l3)
    ;
old_zip([],[],[]);
old_zip([1], [2], ["hi"]);

(*do this*)
fun zip list_triple =
    case list_triple of
        ([],[],[]) => []
        | (hd1 :: tl1, hd2 ::tl2, hd3:: tl3) => (hd1, hd2, hd3) :: zip(tl1, tl2, tl3)
        | _ => raise ListLengthMismatch
        ;
(*妙啊*)
fun unzip lst = 
    case lst of
        [] => ([],[],[])
        | (a, b, c) :: tail => 
            let val (l1, l2 ,l3) = unzip tail
            in (a:: l1, b:: l2, c:: l3)
            end
        ;
val testzip = zip([],[],[]);
val testzip2 = zip([1,2,3],[4,5,6],["a","b","c"]);
val testunzip = unzip([(1,2,3),(4,5,6)]);

(*more nested patterns*)
fun nondecreasing xs = 
    case xs of
        [] => true
        | _ :: [] => true
        | head:: (neck :: rest) => head <= neck andalso nondecreasing (neck:: rest)
        ;
val test_nonde = nondecreasing ([1,2]);

datatype sgn = P|N|Z 
fun multsign (x1, x2) =
    let fun sign x = 
        if x = 0
        then Z 
        else if x>0
        then P
        else N 
    in 
        case (sign x1, sign x2) of 
            (Z, _) => Z
            |( _, Z) => Z
            |(P, P) => P 
            |(N, N) => P
            |_ => N
    end
    ;
val test_muls = multsign(3, ~3);
(*nested patterns can lead to very concise code*)
(*wildcards are good styles*)

(*nested patterns precisely*)
(*pattern a::b::c::d matches all lists with >=3 ele*)
(*pattern a::b::c::[] mathes all lists with 3 ele*)

(*function patterns*)
datatype exp = Constant of int
    |Negate of exp
    |Add of exp * exp
    |MUL of exp * exp
    ;
fun eval e = 
    case e of
        Constant i => i
        |Negate e2 => ~(eval e2)
        |Add(e1, e2) => (eval e1) + (eval e2)
        |MUL(e1, e2) => (eval e1) * (eval e2)
        ;
(*its just syntactic sugar for case expression*)
fun eval2 (Constant i ) = i
    |eval2 (Negate e2) = ~(eval2 e2)
    |eval2 (Add (e1, e2)) = (eval2 e1) + (eval2 e2)
    |eval2 (MUL (e1, e2)) = (eval2 e1) * (eval2 e2)
    ;
(*int list *int list -> int list*)
fun append2 ([], ys) = ys
    |append2 (x::xs, ys) = x::append2(xs, ys)
    ;
val test_eval2 = eval2(Constant 4);
val test_append2 = append2([8],[6]);

(*exceptions*)
fun hd xs =
    case xs of
        [] => raise List.Empty
        |x::_ => x
        ;
hd [];

exception MyOtherException of int * int
raise MyOtherException(3,4);

exception MyUndesirableCondition;
(*int list *exc -> int*)
fun maxlist(xs, ex) = 
    case xs of 
        [] =>raise ex
        |x::[] => x 
        |x::xs' =>Int.max(x, maxlist(xs', ex))
        ;

val test_max = maxlist([1,3,6,2], MyUndesirableCondition);
(* 
e1 handle ex => e2
if e1 evaluates normally, the rest is irrelavent.
but if e1 raises exception listed here, catch the exception and evaluate e2.
if it is not the exception, not handle it and it continues.
with params: e1 handle ex(x, y) =>e2
*)
val catchexc = maxlist([], MyUndesirableCondition)
    handle MyUndesirableCondition => 50;
(*declaring an exception makes adds a constructor for type exn*)

(*tail recursion*)
(*weather recusion is effficient or in what situations does it lead to fast code*)
fun fact n = 
    if n = 0
    then 1
    else n*fact(n-1)
    ; 
(*with a local helper function ,aux, that takes an extra argument*)
fun fact2 n = 
    let fun aux(n, acc) =
        if n = 0
        then acc
        else aux(n-1, acc*n)
    in
        aux(n, 1)
    end
    ;
val x = fact2 3;
(*it is unnessary to keep around a stack-frame just so 
it can get a callee's result without ant further evaluation*)
(*the compiler: remove the caller's stack frame before it makes the call,
the call just reuses the same stack space*)
(*so tail recursion is more efficient!*)

(*accumulators*)
fun sum xs =    
    case xs of 
        [] => 0
        | x:: xs' => x + sum xs'
fun sum2 xs =
    let fun aux(xs, acc) = 
        case xs of 
            [] => acc 
            |x::xs' => aux(xs', acc+x)
    in aux(xs, 0)
    end 
val ll = [1,2,3,4];
sum(ll);
sum2(ll);

fun rev xs = 
    case xs of 
        [] => []
        | x:: xs' => (rev xs') @ [x]
        ;
fun rev2 xs = 
    let fun aux(xs, acc) = 
        case xs of 
            [] => acc
            | x::xs' => aux(xs', x:: acc)
    in aux(xs, [])
    end
    ;
rev ll;
rev2 ll;

(*tail recusive :perspective and definition*)
(*there are cases where recursive function cannot be evaluated in a constant amount of trees*)
(*a tail position is there won't be anything to do afterwards*)

error log

  1. 多重case嵌套要有加括号的习惯,否则有混淆的可能。
  2. arguments 中有record, 一定要将record的组成成分写出来。比如:
fun similar_names (sll, dup:{first:string,last:string,middle:string}) =

PS. 用不惯emacs的小伙伴可以用vscode. 搜索ML 相关插件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值