programming_languages/sml/week2/date.sml

231 lines
5.6 KiB
Standard ML
Raw Normal View History

2020-06-02 03:39:00 +03:00
use "operators.sml";
2020-05-31 18:35:01 +03:00
(* year * month * day *)
type Date = int * int * int
2020-06-02 03:39:00 +03:00
(* can't use pattern matching for now *)
(* fun fold f acc lst =
case lst of
[] => acc
| head :: tail => fold f (f head acc) tail *)
2020-06-01 01:55:44 +03:00
2020-06-02 02:56:53 +03:00
fun fold f acc lst =
if lst = []
then acc
else
let
val tail = tl lst
val head = hd lst
in
fold f (f head acc) tail
end
2020-05-31 18:35:01 +03:00
2020-06-01 15:05:24 +03:00
fun reverse lst =
2020-06-02 02:56:53 +03:00
let
fun f elm acc = elm :: acc
in
fold f [] lst
end
2020-06-01 15:05:24 +03:00
(* non tail optimized :( *)
(* fun filter predicate lst =
case lst of
[] => lst
| head :: tail =>
if predicate head
then head :: filter predicate tail
else filter predicate tail *)
fun filter predicate lst =
let
fun f elm acc = if predicate elm then elm :: acc else acc
in
2020-06-02 02:56:53 +03:00
lst |> fold f [] |> reverse
2020-06-01 15:05:24 +03:00
end
2020-06-02 02:56:53 +03:00
fun range from to =
let
fun generate from to acc =
if from > to
then acc
else generate (from + 1) to (from :: acc)
in
generate from to [] |> reverse
end
2020-06-02 23:34:23 +03:00
fun empty lst = lst = []
(* not efficient but works *)
fun exists elem lst =
filter (fn needle => elem = needle) lst |> empty |> not
fun uniqe lst =
let
fun find_uniqe elem uniqe_elems =
if (exists elem uniqe_elems)
then uniqe_elems
else elem :: uniqe_elems
in
fold find_uniqe [] lst
end
2020-06-02 03:39:00 +03:00
(* naive sort, will blow up the stack. Can't use pattern matching for now :( *)
(* fun sort f lst =
2020-06-02 02:56:53 +03:00
case lst of
[] => []
| hd :: [] => [hd]
| first :: second :: rest =>
if f first second
then second :: first :: sort f rest
2020-06-02 03:39:00 +03:00
else first :: second :: sort f rest *)
(* also will blow up the stack *)
fun sort f lst =
if lst = []
then []
else
if tl lst = []
then lst
else
let
val first = hd lst
val second = hd $ tl lst
val rest = tl $ tl lst
val greater = f first second
in
if greater
then second :: first :: sort f rest
else first :: second :: sort f rest
end
2020-06-02 02:56:53 +03:00
2020-06-01 15:05:24 +03:00
fun is_older ((y1, m1, d1): Date, (y2, m2, d2): Date): bool =
2020-05-31 18:35:01 +03:00
let
val same_dates = y1 = y2 andalso m1 = m2 andalso d1 = d2
val older = y1 <= y2 andalso m1 <= m2 andalso d1 <= d2
in
2020-06-02 02:56:53 +03:00
if same_dates
then false
else older
2020-05-31 18:35:01 +03:00
end
2020-06-01 15:05:24 +03:00
fun number_in_month (dates: Date list, month_to_find: int): int =
2020-05-31 18:35:01 +03:00
let
fun count_month (_, month, _) occurences =
if month = month_to_find
then occurences + 1
else occurences
in
2020-06-02 02:56:53 +03:00
fold count_month 0 dates
2020-05-31 18:35:01 +03:00
end
2020-06-01 15:05:24 +03:00
fun number_in_months (dates: Date list, months_to_find: int list): int =
2020-06-01 01:55:44 +03:00
let
2020-06-01 15:05:24 +03:00
fun count_months month acc =
acc + number_in_month (dates, month)
2020-06-01 01:55:44 +03:00
in
2020-06-02 02:56:53 +03:00
fold count_months 0 months_to_find
2020-06-01 01:55:44 +03:00
end
2020-06-01 15:05:24 +03:00
fun dates_in_month (dates: Date list, in_month: int): Date list =
let
fun filter_dates (_, month, _) = in_month = month
in
filter filter_dates dates
2020-06-02 02:56:53 +03:00
end
fun dates_in_months (dates: Date list, in_months: int list): Date list =
let
fun filter_dates month filtered =
filtered @ dates_in_month (dates, month)
in
fold filter_dates [] in_months
end
fun get_nth (strings: string list, nth: int): string =
let
fun find str (pos, found) =
if pos = nth
then (pos + 1, str)
else (pos + 1, found)
in
fold find (1, "") strings |> #2
end
(* this function will create list for months on every call :( *)
fun date_to_string ((year, month, day): Date): string =
let
val months = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
]
val string_month = get_nth (months, month - 1)
val to_str = Int.toString
fun pad num =
if num < 10
then "0" ^ to_str num
else to_str num
in
string_month ^ " " ^ pad day ^ ", " ^ to_str year
end
fun number_before_reaching_sum (sum: int, numbers: int list): int =
if numbers = [] orelse hd numbers >= sum
then 0
else 1 + number_before_reaching_sum ((sum - hd numbers), tl numbers)
fun what_month (day: int): int =
let
val months = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
in
number_before_reaching_sum (day, months) + 1
end
2020-06-02 03:39:00 +03:00
(* correct but too complex for such problem *)
2020-06-02 02:56:53 +03:00
(* fun month_range (day1: int, day2: int): int list =
let
fun append_month day months = what_month day :: months
in
range day1 day2 |> fold append_month [] |> reverse
end
*)
fun month_range (day1: int, day2: int): int list =
if day1 > day2
then []
else what_month day1 :: month_range (day1 + 1, day2)
fun oldest (dates: Date list): Date option =
let
fun compare a b = not $ is_older (a, b)
in
if dates = []
then NONE
else sort compare dates |> hd |> SOME
2020-06-02 23:34:23 +03:00
end
fun number_in_months_challenge (
dates: Date list,
months_to_find: int list
): int =
number_in_months (dates, uniqe months_to_find)
fun dates_in_months_challenge (
dates: Date list,
in_months: int list
): Date list =
dates_in_months (dates, uniqe in_months)