Skip to content
/ fp-lab1 Public

functional programming at itmo. the first lab

Notifications You must be signed in to change notification settings

pmpknu/fp-lab1

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

48 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

РСшСниС Π·Π°Π΄Π°Ρ‡ Project Euler Π½Π° OCaml

Лабораторная Ρ€Π°Π±ΠΎΡ‚Π° #1

  • Π’Π°Ρ€ΠΈΠ°Π½Ρ‚: 12, 19
  • ΠŸΡ€Π΅ΠΏΠΎΠ΄Π°Π²Π°Ρ‚Π΅Π»ΡŒ ПСнской АлСксандр Π’Π»Π°Π΄ΠΈΠΌΠΈΡ€ΠΎΠ²ΠΈΡ‡
  • Π’Ρ‹ΠΏΠΎΠ»Π½ΠΈΠ» Горляков Π”Π°Π½ΠΈΠΈΠ» ΠŸΠ΅Ρ‚Ρ€ΠΎΠ²ΠΈΡ‡, 367165
  • ИВМО, Π‘Π°Π½ΠΊΡ‚-ΠŸΠ΅Ρ‚Π΅Ρ€Π±ΡƒΡ€Π³, 2024

ОписаниС Ρ€Π°Π±ΠΎΡ‚Ρ‹

Данная лабораторная Ρ€Π°Π±ΠΎΡ‚Π° Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½Π° Π½Π° ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Ρ… ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ΠΎΠ² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΠ³ΠΎ программирования для Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ Π·Π°Π΄Π°Ρ‡ ΠΈΠ· Project Euler. Π Π΅ΡˆΠ΅Π½Π½Ρ‹Π΅ Π·Π°Π΄Π°Ρ‡ΠΈ:

  1. Π—Π°Π΄Π°Ρ‡Π° 12: НахоТдСниС ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ Ρ‚Ρ€Π΅ΡƒΠ³ΠΎΠ»ΡŒΠ½ΠΎΠ³ΠΎ числа с Π±ΠΎΠ»Π΅Π΅ Ρ‡Π΅ΠΌ N дСлитСлями.
  2. Π—Π°Π΄Π°Ρ‡Π° 19: ΠŸΠΎΠ΄ΡΡ‡Π΅Ρ‚ количСства воскрСсСний, Π²Ρ‹ΠΏΠ°Π΄Π°ΡŽΡ‰ΠΈΡ… Π½Π° ΠΏΠ΅Ρ€Π²ΠΎΠ΅ число мСсяца Π·Π° ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½Ρ‹ΠΉ ΠΏΠ΅Ρ€ΠΈΠΎΠ΄.

Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Π° ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°

  • p12/ ΠΈ p19/ β€” Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ с Ρ€Π΅ΡˆΠ΅Π½ΠΈΡΠΌΠΈ Π·Π°Π΄Π°Ρ‡ 12 ΠΈ 19 соотвСтствСнно.
    • lib/ β€” ΠΌΠΎΠ΄ΡƒΠ»ΠΈ ΠΈ Ρ„Π°ΠΉΠ»Ρ‹ с рСализациями Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Ρ… ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ΠΎΠ²:
    • test/ β€” тСсты для ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠΉ, написанныС с использованиСм OUnit2.*

* - Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² p12, Π² p19 ΠΈΡΠΏΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ inline тСсты.

НиТС ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Ρ‹ тСматичСскиС особСнности Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΉ (Π³Π΄Π΅ использована рСкурсия, хвостовая рСкурсия, ΠΌΠΎΠ΄ΡƒΠ»ΡŒΠ½ΠΎΠ΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ ΠΈ ΠΏΡ€.)

let count_factors n =
  let rec aux i =
    if i * i > n
    then 0
    else if n mod i = 0
    then if i * i = n then 1 + aux (i + 1) else 2 + aux (i + 1)
    else aux (i + 1)
  in
  if n <= 0 then 0 else aux 1
;;
let count_factors_tail n =
  let rec aux i count =
    if i * i > n
    then count
    else if n mod i = 0
    then aux (i + 1) (count + if i * i = n then 1 else 2)
    else aux (i + 1) count
  in
  if n <= 0 then 0 else aux 1 0
;;
let result =
  List.filter (fun x -> count_factors_tail x > 500) triangular_numbers
  |> List.fold_left
       (fun acc x ->
         match acc with
         | Some _ -> acc
         | None -> Some x)
       None
;;
let triangular_numbers limit =
  let generate_range n = List.init n (fun i -> i + 1) in
  List.map (fun n -> n * (n + 1) / 2) (generate_range limit)
;;
let triangular_numbers =
  Seq.unfold
    (fun n ->
      let t = n * (n + 1) / 2 in
      Some (t, n + 1))
    1
;;
let find_first_triangular_with_factors n =
  Seq.find (fun x -> count_factors_tail x > n) triangular_numbers
;;
let count_divisors n =
  let count = ref 0 in
  let root = int_of_float (sqrt (float_of_int n)) in
  for i = 1 to root do
    if n mod i = 0 then if i = n / i then incr count else count := !count + 2
  done;
  !count
;;
let find_triangle_with_divisors limit =
  let found = ref false in
  let result = ref 0 in
  let n = ref 1 in
  while not !found do
    let tri_num = triangle_number !n in
    if count_divisors tri_num > limit
    then (
      result := tri_num;
      found := true);
    incr n
  done;
  !result
;;
def count_divisors(n):
    sqrt_n = int(math.sqrt(n))
    count = sum(2 for i in range(1, sqrt_n + 1) if n % i == 0)
    if sqrt_n * sqrt_n == n:
        count -= 1
    return count
def first_triangle_number_with_divisors(limit):
    n = 1
    triangle = 1
    while True:
        divisors = count_divisors(triangle)
        if divisors > limit:
            return triangle
        n += 1
        triangle += n

НиТС ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Ρ‹ тСматичСскиС особСнности Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΉ (Π³Π΄Π΅ использована рСкурсия, хвостовая рСкурсия, ΠΌΠΎΠ΄ΡƒΠ»ΡŒΠ½ΠΎΠ΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ ΠΈ ΠΏΡ€.)

let rec count_sundays year month day_of_week =
  if year > 2000
  then 0
  else (
    let new_count = if day_of_week = 0 then 1 else 0 in
    let days_this_month = days_in_month year month in
    let next_day_of_week = (day_of_week + days_this_month) mod 7 in
    if month == 12
    then new_count + count_sundays (year + 1) 1 next_day_of_week
    else new_count + count_sundays year (month + 1) next_day_of_week)
;;
let rec count_sundays year month day_of_week count =
  if year > 2000
  then count
  else (
    let new_count = if day_of_week = 0 then count + 1 else count in
    let days_this_month = days_in_month year month in
    let next_day_of_week = (day_of_week + days_this_month) mod 7 in
    if month == 12
    then count_sundays (year + 1) 1 next_day_of_week new_count
    else count_sundays year (month + 1) next_day_of_week new_count)
;;
let count_sundays start_year end_year =
  let years = List.init (end_year - start_year + 1) (fun i -> start_year + i) in
  let aux year =
    let months = List.init 12 (fun m -> m + 1) in
    List.filter (fun month -> zellers_congruence year month 1 = 0) months |> List.length
  in
  List.fold_left (fun acc year -> acc + aux year) 0 years
;;
let count_sundays start_year end_year =
  let years = List.init (end_year - start_year + 1) (fun i -> start_year + i) in
  let aux year =
    let months = List.init 12 (fun m -> m + 1) in
    let map_filter month = if zellers_congruence year month 1 = 0 then 1 else 0 in
    List.fold_left ( + ) 0 (List.map map_filter months)
  in
  List.fold_left (fun acc year -> acc + aux year) 0 years
;;
let count_sundays start_year end_year =
  let count = ref 0 in
  for year = start_year to end_year do
    for month = 1 to 12 do
      if zellers_congruence year month 1 = 0 then incr count
    done
  done;
  !count
;;
for year in range(1901, 2001):
    for month in range(1, 13):
        first_day = datetime(year, month, 1)
        if first_day.weekday() == 6:
            sundays_count += 1

Π’Ρ‹Π²ΠΎΠ΄Ρ‹

OCaml показался ΠΌΠ½Π΅ достаточно простым ΠΈ понятным ΠΏΠΎ синтаксису, ΠΎΠ΄Π½Π°ΠΊΠΎ, ΠΏΡ€ΠΈ поискС сталкивался с ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°ΠΌΠΈ Π½Π° Haskell ΠΈ Π½Π΅ ΠΏΠΎΠ½ΠΈΠΌΠ°Π», ΠΏΠΎΡ‡Π΅ΠΌΡƒ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ Ρ‚Π°ΠΊ услоТняСт мСстами.

Π― познакомился с Ρ‚Π°ΠΊΠΈΠΌΠΈ функциями, ΠΊΠ°ΠΊ List.map, List.filter ΠΈ List.fold, ΠΎΠ½ΠΈ сдСлали ΠΊΠΎΠ΄ Π±ΠΎΠ»Π΅Π΅ ΠΊΠΎΠΌΠΏΠ°ΠΊΡ‚Π½Ρ‹ΠΌ ΠΈ понятным. ИспользованиС Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ filter для отсСивания нСподходящих Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ Π΄Π΅Π»Π°Π΅Ρ‚ ΠΊΠΎΠ΄ Π±ΠΎΠ»Π΅Π΅ Π΄Π΅ΠΊΠ»Π°Ρ€Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΌ.

Π’Π°ΠΊΠΆΠ΅ я воспользовался Π»Π΅Π½ΠΈΠ²Ρ‹ΠΌΠΈ коллСкциями (Seq), для Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ бСсконСчного количСства Ρ‚Ρ€Π΅ΡƒΠ³ΠΎΠ»ΡŒΠ½Ρ‹Ρ… чисСл, Ρ‡Ρ‚ΠΎ Π·Π° счСт Π»Π΅Π½ΠΈ ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈΠ»ΠΎ ΠΎΠ±Ρ€Π°Ρ‚ΠΈΡ‚ΡŒΡΡ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΊ Π½ΡƒΠΆΠ½ΠΎΠΌΡƒ количСству Ρ‚Ρ€Π΅ΡƒΠ³ΠΎΠ»ΡŒΠ½Ρ‹Ρ… чисСл ΠΈ Π½Π΅ Π½ΡƒΠΆΠ½ΠΎ Π±Ρ‹Π»ΠΎ ΠΏΡ€ΠΈΠ΄ΡƒΠΌΡ‹Π²Π°Ρ‚ΡŒ, ΠΊΠ°ΠΊ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π΅.

Π’Ρ‚ΠΎΡ€ΡƒΡŽ (p19) Π·Π°Π΄Π°Ρ‡Ρƒ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΎΡΡŒ Ρ€Π΅ΡˆΠΈΡ‚ΡŒ Π±ΠΎΠ»Π΅Π΅ качСствСнно, Π½Π° ΠΌΠΎΠΉ взгляд, вСроятнСС всСго благодаря Ρ‚ΠΎΠΌΡƒ, Ρ‡Ρ‚ΠΎ ΡƒΠΆΠ΅ разобрался с синтаксисом ΠΈ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Π°ΠΌ ΠΊ Ρ€Π΅ΡˆΠ΅Π½ΠΈΡŽ Π·Π°Π΄Π°Ρ‡. Π’Π΅ΠΌ Π½Π΅ ΠΌΠ΅Π½Π΅Π΅, Π±Ρ‹Π»ΠΎ тяТСло ΠΏΡ€ΠΈΠ΄ΡƒΠΌΡ‹Π²Π°Ρ‚ΡŒ Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Π΅ способы Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ достаточно ΠΎΠ΄Π½ΠΎΠ³ΠΎ Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ.

Запуск тСстов

Для запуска тСстов с использованиСм OUnit2:

dune runtest

Зависимости

Для сборки ΠΈ запуска ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΈΠΌΠ΅Ρ‚ΡŒ:

  • OCaml >= 4.12.0
  • Dune >= 2.0
  • OUnit2
  • ppx_inline_test

About

functional programming at itmo. the first lab

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published