카테고리 없음

[Ocaml] 기초 연습 1

김호록님 2022. 11. 15. 23:14

연구실에서 사용하는 언어가 Ocaml이기 때문에, 공부 기록을 남겨보려고 한다.

Ocaml은 함수형 언어이기 때문에 java와 같은 객체지향형 언어와는 차이를 보인다.

구글링을 통해 Ocaml을 실행하는 데에 필요한 melrin 등의 라이브러리 설치를 완료했다.

 

https://www.youtube.com/watch?v=uJ3_bNQPixQ&t=1624s 

 

1. 피보나치 함수

let rec fib x = 
  if x = 0 then 1
  else x * fib(x-1)

rec 는 재귀 함수 작성 시 사용한다.

─( 21:45:31 )─< command 0 >───────────────────────────────────────────────────────{ counter: 0 }─
utop # #use "test1.ml";;
val fib : int -> int = <fun>
─( 21:45:31 )─< command 1 >───────────────────────────────────────────────────────{ counter: 0 }─
utop # fib 3;;
- : int = 6
─( 21:45:39 )─< command 2 >───────────────────────────────────────────────────────{ counter: 0 }─
utop # fib 2;;
- : int = 2

 

2. 원의 넓이를 구하는 함수

let rec circle_area r =
  3.14 *. r *. r

float 타입 사용 시 . 을 써줘야 한다.

utop # #use "test1.ml";;
val circle_area : float -> float = <fun>
─( 22:09:26 )─< command 1 >───────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # circle_area 3;;
Error: This expression has type int but an expression was expected of type
         float
  Hint: Did you mean `3.'?
─( 22:09:33 )─< command 2 >───────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # circle_area 3.;;
- : float = 28.274333882308138

. 을 사용해주지 않으면 오류가 뜨게 된다.

 

3. 거듭 제곱 함수

let rec power n x = (* x^n *)
  if n = 0 then 1 
  else power(n-1) x * x;;
─( 22:09:41 )─< command 3 >───────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # #use "power.ml";;
val power : int -> int -> int = <fun>
─( 22:09:46 )─< command 4 >───────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # power 3 2;;
- : int = 8

 

4. 두 리스트를 붙이는 함수

let rec append l1 l2 =
  match l1 with
  | [] -> l2
  | h :: t -> h :: append t l2

:: 는 원소와 리스트를 결합할 때 사용한다.

l1이 빈 리스트 일 때는 l2를 리턴한다.

빈 리스트가 아닐 경우에는 head를 붙이고, append를 다시 호출하여 남은 tail(= l1) 과 l2를 넣어 호출한다.

이를 l1이 빈 리스트가 될 때까지 실행한다.

utop # #use "append.ml";;
val append : 'a list -> 'a list -> 'a list = <fun>
─( 22:25:28 )─< command 6 >───────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # append [1;2;3] [4;5;6];;
- : int list = [1; 2; 3; 4; 5; 6]
─( 22:42:14 )─< command 7 >───────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # append [2;4;6] [8;10];;
- : int list = [2; 4; 6; 8; 10]

 

5. 리스트 원소들을 reverse 하는 함수

let rec reverse l =
  match l with
  | [] -> []
  | h :: t ->  reverse t @ [h]

@ 는 리스트와 리스트를 결합할 때 사용한다.

빈 리스트일 경우 빈 리스트를 리턴한다.

빈 리스트가 아닐 경우 reverse 함수에 tail 값을 입력한 함수를 호출하고 뒤에 head가 담긴 리스트를 붙여 호출한다.

이를 l이 빈 리스트가 될 때까지 실행한다.

utop # #use "reverse.ml";;
val reverse : 'a list -> 'a list = <fun>
─( 22:42:39 )─< command 9 >───────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # reverse [1;2;3];;
- : int list = [3; 2; 1]
─( 22:51:29 )─< command 10 >──────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # reverse ["C"; "Java"; "Ocaml"];;
- : string list = ["Ocaml"; "Java"; "C"]

 

6. n번째 원소를 리턴하는 함수

let rec nth l n =
  match l with
  | [] -> raise (Failure "nth")
  | h::t -> if n = 0 then h 
    else nth t (n-1);;

빈 리스트이면 Faliure "nth"를 출력한다.

빈 리스트가 아니면, n = 0일 경우 0번째 원소, 즉 head를 리턴한다.

n = 0이 아닐 경우 nth에 tail(= l) 과 n-1을 입력으로 넣어 호출한다.

이를 n = 0이 될 때까지 실행한다.

─( 22:55:36 )─< command 2 >──────────────────────────────────────────────────────────────{ counter: 0 }─
utop # nth [1;2;3;4] 0;;
- : int = 1
─( 22:57:26 )─< command 3 >──────────────────────────────────────────────────────────────{ counter: 0 }─
utop # nth [2;4;8] 2;;
- : int = 8
─( 22:57:40 )─< command 4 >──────────────────────────────────────────────────────────────{ counter: 0 }─
utop # nth [1;2;3;4] 5;;
Exception: Failure "nth".

 

7. 리스트에서 첫 번째로 위치한 원소를 지우는 함수

let rec remove_first a l =
  match l with
  | [] -> []
  | h :: t -> if  h = a then t
  else h :: remove_first a t

빈 리스트일 경우 빈 리스트를 리턴한다.

빈 리스트가 아닐 경우, head = a이면 tail만을 리턴한다.

head = a가 아니면 head는 그대로 붙이고 remove_first에 a와 head를 제외한 tail을 입력으로 넣어 호출한다.

이를 head = a일 때까지 실행한다.

─( 22:57:52 )─< command 5 >──────────────────────────────────────────────────────────────{ counter: 0 }─
utop # #use "remove_first.ml";;
val remove_first : 'a -> 'a list -> 'a list = <fun>
─( 22:57:59 )─< command 6 >──────────────────────────────────────────────────────────────{ counter: 0 }─
utop # remove_first 2 [1;2;3;4;2];;
- : int list = [1; 3; 4; 2]
─( 23:07:53 )─< command 7 >──────────────────────────────────────────────────────────────{ counter: 0 }─
utop # remove_first 4 [1;2];;
- : int list = [1; 2]
─( 23:08:11 )─< command 8 >──────────────────────────────────────────────────────────────{ counter: 0 }─
utop # remove_first [1;2] [[1;2;3]; [1;2]; [3;4]];;
- : int list list = [[1; 2; 3]; [3; 4]]

 

8. 원소를 리스트에 넣는 함수 (작은 순으로 정렬)

let rec insert a l =
  match l with
  | [] -> [a]
  | h :: t ->  if a <= h then a :: l
  else h :: insert a t

빈 리스트일 경우 리스트에 원소(a)를 넣어 리턴한다.

빈 리스트가 아닐 경우, a가 head보다 작거나 같으면 a와 전체 리스트를 붙인다.

a가 head보다 크면 앞에 head를 붙이고 insert에 a와 tail을 넣어 호출한다.

이를 a가 head보다 작거나 같을 때까지 실행한다.

 

9. 원소 크기 순 정렬 함수

let rec insert a l =
  match l with
  | [] -> [a]
  | h :: t ->  if a <= h then a :: l
  else h :: insert a t

let rec sort l =
  match l with
  | [] -> []
  | h::t -> insert h (sort t)

빈 리스트이면 빈 리스트를 리턴한다.

빈 리스트가 아닐 경우, insert에 head와 sort t를 넣어 호출한다.

이를 tail이 빈 리스트가 될 때까지 실행한다.

utop # #use "insertion sort.ml";;
val insert : 'a -> 'a list -> 'a list = <fun>
val sort : 'a list -> 'a list = <fun>
─( 23:39:35 )─< command 18 >─────────────────────────────────────────────────────────────{ counter: 0 }─
utop # sort [4;2;6;8];;
- : int list = [2; 4; 6; 8]
─( 23:39:43 )─< command 19 >─────────────────────────────────────────────────────────────{ counter: 0 }─
utop # sort [1;2;1;5];;
- : int list = [1; 1; 2; 5]