这次回顾HW1 Extra Practice Problems,主要是Standard ML的基本语法的补充练习。

课程主页:

https://www.coursera.org/learn/programming-languages/home

B站搬运:

https://www.bilibili.com/video/BV1dL411j7L7

习题内容:

https://www.coursera.org/learn/programming-languages/supplement/U9go7/extra-practice-problems

参考资料:

代码

(* helper function *)
fun append (xs : int list, ys : int list) =
    if null xs
    then ys
    else hd (xs) :: append (tl(xs), ys)

(* problem 1 *)  
fun alternate(arr: int list) = 
    let
      fun helper(arr: int list, sign: int) = 
        if null arr
        then 0
        else
            (hd arr) * sign + helper((tl arr), (~1) * sign)
    in
      helper(arr, 1)
    end

(* problem 2 *)
fun min_max(arr: int list) = 
    let 
        fun max(a: int, b: int) = 
            if a >= b
            then a
            else b
        fun min(a: int, b: int) = 
            if a >= b
            then b
            else a
        fun helper(arr: int list, min_num: int, max_num: int) = 
            if null arr
            then (min_num, max_num)
            else helper((tl arr), min(min_num, (hd arr)), max(max_num, (hd arr)))
    in
        helper(arr, (hd arr), (hd arr))
    end

(* problem 3 *)  
fun cumsum(arr: int list) = 
    let
      fun helper(arr: int list, par_sum: int) = 
        if null arr
        then
            []
        else
            let
              val a = par_sum + (hd arr)
            in
              a::helper((tl arr), a)
            end
    in
      helper(arr, 0)
    end

(* problem 4 *)  
fun greeting(name: string option) = 
    if isSome name
    then "Hello there, " ^ (valOf name) ^ "!"
    else "Hello there, you!"

(* problem 5 *)  
fun repeat(arr1: int list, arr2: int list) = 
    let
      fun helper(a: int, n: int) = 
        if n = 0
        then
            []
        else
            a::helper(a, n - 1)

    in
        if null arr1
        then
            []
        else
            append(helper((hd arr1), (hd arr2)), repeat((tl arr1), (tl arr2)))
    end

(* problem 6 *)
fun addOpt(a: int option, b: int option) = 
    if (isSome a) andalso (isSome b)
    then
        SOME ((valOf a) + (valOf b))
    else
        NONE

(* problem 7 *)  
fun addAllOpt(arr: int option list) = 
    let
      fun addOpt(a: int option, b: int option) = 
        if (isSome a) andalso (isSome b)
        then
            SOME ((valOf a) + (valOf b))
        else
            if (isSome a)
            then
                SOME (valOf a)
            else
                if (isSome b)
                then
                    SOME (valOf b)
                else
                    NONE
      fun helper(arr: int option list, res: int option) = 
        if null arr
        then res
        else
            helper((tl arr), addOpt(res, (hd arr)))
    in
      helper(arr, NONE)
    end

(* problem 8 *)  
fun any(arr: bool list) = 
    if null arr
    then false
    else
        if (hd arr)
        then true
        else any((tl arr))

(* problem 9 *)  
fun all(arr: bool list) = 
    if null arr
    then true
    else
        if not (hd arr)
        then false
        else all((tl arr))

(* problem 10 *) 
fun zip(arr1: int list, arr2: int list) = 
    let
      fun helper(arr1: int list, arr2: int list) = 
        if (null arr1) orelse (null arr2)
        then
            []
        else
            ((hd arr1), (hd arr2))::helper((tl arr1), (tl arr2))
    in
      helper(arr1, arr2)
    end

(* problem 11 *) 
fun zipRecycle(arr1: int list, arr2: int list) = 
    let
      fun len(arr: int list) = 
        if null arr
        then 0
        else 1 + len((tl arr))
      fun get_i(arr: int list, i: int) = 
        let
          val n = len(arr)
        in
          if i >= n
          then get_i(arr, (i mod n))
          else
            if i = 0
            then 
                (hd arr)
            else
                get_i((tl arr), i - 1)
        end
      fun max(a: int, b: int) = 
        if a > b
        then a
        else b
      val len1 = len(arr1)
      val len2 = len(arr2)
      val len = max(len1, len2)
      fun helper(arr1: int list, arr2: int list, i: int) = 
        if i = len
        then
            []
        else
            (get_i(arr1, i), get_i(arr2, i))::helper(arr1, arr2, i + 1)
    in
      helper(arr1, arr2, 0)
    end

(* problem 12 *) 
fun zipOpt(arr1: int list, arr2: int list) = 
    let
      fun len(arr: int list) = 
        if null arr
        then 0
        else 1 + len((tl arr))
      fun helper(arr1: int list, arr2: int list) = 
        if (null arr1) orelse (null arr2)
        then
            []
        else
            ((hd arr1), (hd arr2))::helper((tl arr1), (tl arr2))
      val l1 = len(arr1)
      val l2 = len(arr2)
      val flag = (l1 = l2)
    in
      if flag
      then 
        SOME (zip(arr1, arr2))
      else
        NONE
    end

(* problem 13 *) 
fun lookup(table: (string * int) list, s: string) = 
    if null table
    then
        NONE
    else
        let
          val pair = (hd table)
        in
          if (#1 pair) = s
          then SOME (#2 pair)
          else lookup((tl table), s)
        end

(* problem 15 *) 
fun splitAt(arr: int list, threshold: int) = 
    let
      fun helper(arr: int list, small: int list, big: int list) = 
        if
            null arr
        then
            (small, big)
        else
            if (hd arr) < threshold
            then
                helper((tl arr), append(small, [(hd arr)]), big)
            else
                helper((tl arr), small, append(big, [(hd arr)]))
    in
      helper(arr, [], [])
    end

(* problem 14 *) 
fun splitup(arr: int list) = 
    splitAt(arr, 0)

(* problem 16 *) 
fun isSorted(arr: int list) = 
    if null arr
    then
        true
    else
        if null (tl arr)
        then true
        else
            if (hd arr) > (hd (tl arr))
            then false
            else isSorted((tl arr))

(* problem 17 *) 
fun isIncreasingSorted(arr: int list) = 
    isSorted(arr)

fun isDecreasingSorted(arr: int list) = 
    if null arr
    then
        true
    else
        if null (tl arr)
        then true
        else
            if (hd arr) <= (hd (tl arr))
            then false
            else isDecreasingSorted((tl arr))

fun isAnySorted(arr: int list) = 
    isIncreasingSorted(arr) orelse isDecreasingSorted(arr)

(* problem 18 *) 
fun sortedMerge(arr1: int list, arr2: int list) = 
    let
      fun helper(arr1: int list, arr2: int list, res: int list) = 
        if null arr1
        then 
            append(res, arr2)
        else
            if null arr2
            then
                append(res, arr1)
            else
                if (hd arr1) < (hd arr2)
                then
                    helper((tl arr1), arr2, append(res, [(hd arr1)]))
                else
                    helper(arr1, (tl arr2), append(res, [(hd arr2)]))
    in
      helper(arr1, arr2, [])
    end

(* problem 19 *) 
fun qsort(arr: int list) = 
    if null arr
    then
        []
    else
        if null (tl arr)
        then 
            arr
        else
            let
                val a = (hd arr)
                val p = splitAt(arr, a)
                val sorted_small = qsort((#1 p))
                val sorted_big = qsort((tl (#2 p)))
            in
                (* sortedMerge(sorted_small, sorted_big) *)
                append(sorted_small, a::sorted_big)
            end

(* problem 20 *) 
fun divide(arr: int list) = 
    let
      fun helper(arr: int list, r1: int list, r2: int list, flag: int) = 
      if null arr
      then
        (r1, r2)
      else
        if flag = 0
        then
          helper((tl arr), append(r1, [(hd arr)]), r2, 1 - flag)
        else
          helper((tl arr), r1, append(r2, [(hd arr)]), 1 - flag)
    in
      helper(arr, [], [], 0)
    end

(* problem 21 *) 
fun not_so_quick_sort(arr: int list) = 
    if null arr
    then 
        []
    else
        if null (tl arr)
        then 
            arr
        else
            let
                val p = divide(arr)
                val arr1 = (#1 p)
                val arr2 = (#2 p)
            in
                sortedMerge(not_so_quick_sort(arr1), not_so_quick_sort(arr2))
    end

(* problem 22 *) 
fun fullDivide(k: int, n: int) = 
    let
      fun helper(n: int, d: int) = 
        if not ((n mod k) = 0)
        then
            (d, n)
        else
            helper(n div k, d + 1)
    in
      helper(n, 0)
    end

(* problem 23 *) 
fun factorize(n: int) = 
    let
      fun append (xs : (int * int) list, ys : (int * int) list) =
        if null xs
        then ys
        else hd (xs) :: append (tl(xs), ys)
      fun helper(m: int, d: int, res: (int * int) list) =
        if m = 1
        then
            res
        else
            let
                val p = fullDivide(d, m)
                val t = (#1 p)
            in
                if t = 0
                then
                    helper((#2 p), d + 1, res)
                else
                    helper((#2 p), d + 1, append(res, [(d, t)]))
            end
    in
      helper(n, 2, [])
    end

(* problem 24 *) 
fun multiply(arr: (int * int) list) = 
    let
      fun exp(k: int, n: int) = 
        if n = 0
        then 1
        else k * exp(k, n - 1)
      fun helper(arr: (int * int) list, res: int) = 
        if null arr
        then
            res
        else
            helper((tl arr), exp((hd arr)) * res)
    in
      helper(arr, 1)
    end

(* problem 25 *)
fun all_products(arr: (int * int) list) = 
    let
      (* d ^ 0, ... , d ^ 1, 递增 *)
      fun get_products(d: int, k: int, res: int) = 
        if k = 0
        then
            [res]
        else
            res::get_products(d, k - 1, res * d)
      (* arr中每个元素乘以d, 保持递增 *)
      fun prod_arr(d: int, arr: int list) = 
        let
          fun helper(arr: int list, res: int list) = 
            if null arr
            then
                res
            else
                helper((tl arr), append(res, [d * (hd arr)]))
        in
          helper(arr, [])
        end
      (* for d in arr1, 计算prod_arr, 然后merge *)
      fun prod_helper(arr1: int list, arr2: int list) = 
        if null arr1
        then
            []
        else
            let
                val r1 = prod_arr((hd arr1), arr2)
                val r2 = prod_helper((tl arr1), arr2)
            in
                sortedMerge(r1, r2)
            end
      fun helper(arr: (int * int) list) = 
        if null arr
        then
            []
        else
            if null (tl arr)
            then
                get_products((#1 (hd arr)), (#2 (hd arr)), 1)
            else
                let
                  val arr1 = get_products((#1 (hd arr)), (#2 (hd arr)), 1)
                  val arr2 = helper((tl arr))
                in
                  prod_helper(arr1, arr2)
                end
    in
      helper(arr)
    end

测试

use "hw1_extra.sml";

val test1_1 = alternate ([1, 2, 3, 4]) = ~2
val test1_2 = alternate ([1, 2, 4, 3]) = 0

val test2_1 = min_max ([1, 2, 3, 4]) = (1, 4)
val test2_2 = min_max ([9, 8, 3, 7]) = (3, 9)

val test3_1 = cumsum ([1, 2, 3, 4]) = [1, 3, 6, 10]
val test3_2 = cumsum ([9, 8, 3, 7]) = [9, 17, 20, 27]

val test4_1 = greeting (SOME "Tom") = "Hello there, Tom!"
val test4_2 = greeting (NONE) = "Hello there, you!"

val test5_1 = repeat ([1,2,3], [4,0,3]) = [1,1,1,1,3,3,3]
val test5_2 = repeat ([1,2], [5, 6]) = [1,1,1,1,1,2,2,2,2,2,2]

val test6_1 = addOpt (SOME 1, SOME 4) = SOME 5
val test6_2 = addOpt (SOME 1, NONE) = NONE
val test6_3 = addOpt (NONE, SOME 2) = NONE
val test6_4 = addOpt (NONE, NONE) = NONE

val test7_1 = addAllOpt ([SOME 1, NONE, SOME 3]) = SOME 4
val test7_2 = addAllOpt ([NONE, NONE, NONE]) = NONE

val test8_1 = any ([true, false, false]) = true
val test8_2 = any ([false, false, false]) = false
val test8_3 = any ([]) = false

val test9_1 = all ([true, false, false]) = false
val test9_2 = all ([false, false, false]) = false
val test9_3 = all ([]) = true
val test9_4 = all ([true, true]) = true

val test10_1 = zip ([1,2,3], [4, 6]) = [(1,4), (2,6)]

val test11_1 = zipRecycle ([1,2,3], [4, 6]) = [(1,4), (2,6), (3, 4)]
val test11_2 = zipRecycle ([1,2,3], [1, 2, 3, 4, 5, 6, 7]) = [(1,1), (2,2), (3, 3), (1,4), (2,5), (3,6), (1,7)]

val test12_1 = zipOpt ([1,2,3], [4, 6]) = NONE
val test12_2 = zipOpt ([1,2], [4, 6]) = SOME [(1, 4), (2, 6)]

val test13_1 = lookup([("abc", 1), ("tom", 2)], "abc") = SOME 1
val test13_2 = lookup([("abc", 1), ("tom", 2)], "def") = NONE

val test14_1 = splitup([1, 6, 5, 4, 2]) = ([], [1, 6, 5, 4, 2])
val test14_2 = splitup([~1, ~6, ~5, ~4, ~2]) = ([~1, ~6, ~5, ~4, ~2], [])
val test14_3 = splitup([3, ~6, 6, ~4, ~2]) = ([~6, ~4, ~2], [3, 6])

val test15_1 = splitAt([1, 6, 5, 4, 2], 3) = ([1, 2], [6, 5, 4])
val test15_2 = splitAt([1, 6, 5, 4, 2], 5) = ([1, 4, 2], [6, 5])

val test16_1 = isSorted([1, 2, 3]) = true
val test16_2 = isSorted([1, 5, 3]) = false

val test17_1 = isAnySorted([1, 2, 3]) = true
val test17_2 = isAnySorted([1, 5, 3]) = false
val test17_3 = isAnySorted([7, 5, 3]) = true

val test18_1 = sortedMerge ([1,4,7], [5,8,9]) = [1,4,5,7,8,9]

val test19_1 = qsort ([]) = []
val test19_2 = qsort ([1]) = [1]
val test19_3 = qsort ([2, 1]) = [1, 2]
val test19_4 = qsort ([2, 1, 3]) = [1, 2, 3]
val test19_5 = qsort ([6, 10, 5, 3, 2, 11, 12]) = [2, 3, 5, 6, 10, 11, 12]

val test20_1 = divide ([1,2,3,4,5,6,7]) = ([1,3,5,7], [2,4,6])

val test21_1 = not_so_quick_sort ([]) = []
val test21_2 = not_so_quick_sort ([1]) = [1]
val test21_3 = not_so_quick_sort ([2, 1]) = [1, 2]
val test21_4 = not_so_quick_sort ([2, 1, 3]) = [1, 2, 3]
val test21_5 = not_so_quick_sort ([6, 10, 5, 3, 2, 11, 12]) = [2, 3, 5, 6, 10, 11, 12]

val test22_1 = fullDivide (2, 40) = (3, 5)
val test22_2 = fullDivide((3,10)) = (0, 10)

val test23_1 = factorize(20) = [(2,2), (5,1)]
val test23_2 = factorize(36) = [(2,2), (3,2)]
val test23_3 = factorize(1) = []

val test24_1 = multiply([(2,2), (5,1)]) = 20
val test24_2 = multiply([(2,2), (3,2)]) = 36

val test25_1 = all_products([(2,2), (5,1)]) = [1,2,4,5,10,20]
val test25_2 = all_products([(2,2)]) = [1,2,4]

(* https://gist.github.com/gbaptista/c3e92d00b729515bd63865b299143e76#file-tests-sml *)
val test1 = alternate([1,2,3,4]) = ~2;

val test2 = min_max([5,1,3,8,4,2,3]) = (1, 8);

val test3 = cumsum([1,4,20,30]) = [1,5,25,55];

val test4 = greeting(NONE) = "Hello there, you!"

val test4b = greeting(SOME "gbaptista") = "Hello there, gbaptista!"

val test5 = repeat([1,2,3], [4,0,3]) = [1,1,1,1,3,3,3]

val test6 = addOpt(SOME 2, SOME 3) = SOME 5
val test6b = addOpt(SOME 2, NONE) = NONE
val test6c = addOpt(NONE, SOME 3) = NONE
val test6d = addOpt(NONE, NONE) = NONE

val test7 = addAllOpt ([SOME 1, NONE, SOME 3]) = SOME 4

val test8 = any([]) = false
val test8b = any([false, false, true, false]) = true
val test8c = any([false, false]) = false

val test9 = all([]) = true
val test9b = all([false, false, true, false]) = false
val test9c = all([false, false]) = false
val test9d = all([true, true, true]) = true

val test10 = zip ([1,2,3], [4,6]) = [(1,4), (2,6)]

val test11 = zipRecycle([1,2,3], [1,2,3,4,5,6,7]) = [(1,1), (2,2), (3,3),(1,4),(2,5),(3,6),(1,7)]

val test12 = zipOpt ([1,2,3], [4,6]) = NONE
val test12b = zipOpt ([1,2], [4,6]) = SOME [(1,4), (2,6)]

val test13 = lookup ([("test", 3), ("lorm", 7)], "a") = NONE
val test13b = lookup ([("test", 3), ("lorm", 7)], "test") = SOME 3
val test13c = lookup ([("test", 3), ("lorm", 7)], "lorm") = SOME 7

val test14 = splitup ([1,2,3,4,0,~4,~5,~1,2,~7]) = ([~4,~5,~1,~7],[1,2,3,4,0,2])

val test15 = splitAt ([8,4,1,0,2,9,3,7,1,4], 4) = ([1,0,2,3,1],[8,4,9,7,4])

val test16 = isSorted ([1,2,3]) = true
val test16b = isSorted ([1,2,3,0]) = false
val test16c = isSorted ([1,1]) = true

val test17 = isAnySorted([1,2,3]) = true
val test17b = isAnySorted([3,2,1]) = true
val test17c = isAnySorted([3,2,1,4]) = false

val test18 = sortedMerge([1,4,7],[5,8,9]) = [1,4,5,7,8,9]
val test18b = sortedMerge([1,4,7],[5,8,9,10,11,13]) = [1,4,5,7,8,9,10,11,13]
val test18c = sortedMerge([1,2,3,4],[5,8,9]) = [1,2,3,4,5,8,9]
val test18d = sortedMerge([1],[2]) = [1,2]
val test18e = sortedMerge([2],[1]) = [1,2]
val test18f = sortedMerge([2,3],[0]) = [0,2,3]

val test19 = qsort([11, 13,1,42,2,11,3,2,14,8,7]) = [1,2,2,3,7,8,11,11,13,14,42]
val test19b = qsort([2,1]) = [1,2]
val test19c = qsort([2,1,4,2,3,0,9]) = [0,1,2,2,3,4,9]
val test19d = qsort([1]) = [1]
val test19e = qsort([]) = []

val test20 = divide([1,2,3,4,5,6,7,8,9]) = ([1,3,5,7,9],[2,4,6,8])
val test20b = divide([1,2,3]) = ([1,3],[2])
val test20c = divide([1,2]) = ([1],[2])
val test20d = divide([1]) = ([1],[])
val test20e = divide([]) = ([],[])

val test21 = not_so_quick_sort([11, 13,1,42,2,11,3,2,14,8,7]) = [1,2,2,3,7,8,11,11,13,14,42]
val test21b = not_so_quick_sort([2,1]) = [1,2]
val test21c = not_so_quick_sort([2,1,4,2,3,0,9]) = [0,1,2,2,3,4,9]
val test21d = not_so_quick_sort([1]) = [1]
val test21e = not_so_quick_sort([]) = []

val test22 = fullDivide(2,40) = (3,5)
val test22b = fullDivide(3,10) = (0,10)

val test23 = factorize(20) = [(2,2),(5,1)]
val test23b = factorize(36) = [(2,2),(3,2)]
val test23c = factorize(878698923) = [(3,1),(23,1),(937,1),(13591,1)]

val test24 = multiply([(2,2),(5,1)]) = 20
val test24b = multiply([(2,2),(3,2)]) = 36
val test24c = multiply([(3,1),(23,1),(937,1),(13591,1)]) = 878698923

val test25 = all_products([(2,2),(5,1)]) = [1,2,4,5,10,20]
val test25b = all_products([(2,2),(3,2)]) = [1,2,3,4,6,9,12,18,36]
val test25c = all_products([(2,1),(3,1)]) = [1,2,3,6]
val test25d = all_products([(2,1),(3,1),(5,1)]) = [1,2,3,5,6,10,15,30]