[PL] Ocaml : Basic

parkheeddong·2023년 6월 4일
0
post-thumbnail

Ocaml Basic

1. 주석(comment)

여러줄의 주석만 지원된다.
(* write your comment here *)



2. 변수(Variables)

1) 전역변수(global variable)

let [variable] = [expression]
✔ expression의 값이 계산된 후, variable에 bound 된다.

let x = 3 + 4;;
✔ 변수가 "값 7로 바운드 되었다(variable x is bound to value 7)"고 한다.

이 값은 바뀔 수 없음!


-> 자료형을 명시하지 않았지만 ocaml은 w,x는 int형으로 y,z는 string형으로 type inference를 한다.

2) 지역변수(local variable)

let [variable] = [expression1] in [expression2]
✔ let : 변수 선언
✔ in : 변수의 범위(scope)

let x = e1 in e2
✔ e1의 값이 계산된 후 x에 bound된다. 단, x가 사용될 수 있는 scope는 e2이다.
✔ e2의 값은 전체 expression의 값이 된다.


첫 번째 '전체' exrpression의 값은 3, 두번째는 6, 세번째는 4가 된다.

🔔 Ocaml에서 변수는 값 변경이 불가능하다. (Variables are immutable)

  • 한번 변수에 값이 bound된다면 변경할 수 없다.
  • 두 개의 변수가 같은 이름을 가진다면 variable shadowing이 일어난다.

let x = 1 in 		// a
let x = x + x 		// b
// a와 b의 x는 다른 변수이며, 각각 다른 변수가 선언된 것이다. -> variable shadowing. 
in x // 가장 최근에 적용한 x를 reference하게 된다. (b의 x) -> 2 return

Examples

let a = 1 in a;;
let a = 1 in a * 2;;
let a = 1 in let b = a + a in let c = b + b in c + c;;
Let d = let a = 1 in let b = a + a in let c = b + b in c + c;;  


3. Sequencing

연속적인 unit expression의 계산을 수행한다.

nothing, non, void 등 아무값도 아닌 것을 'Unit Expression'이라고 한다.
(evaluate consecutive unit expressions)

Sequencing은 Unit을 리턴하는 Expression들을 연속적으로 계산하는 것으로서, 세미콜론으로 연결한다.

마지막 Expression에는 세미콜론이 붙지 않는다.

Semicolon-only 방식을 사용할 수도 있지만, begin-end 방식(앞뒤에 괄호를 붙이는 것과 유사한 개념)을 사용하는 것이 더 일반적이다!



4. 함수

1) First class value

value가 first class인 것은 아래 3가지 조건을 만족하는 것이다.
(1) variable에 저장되어야한다.
(2) function의 파라미터로 전달될 수 있어야 한다.
(3) function의 리턴값으로도 사용할 수 있어야 한다.

  • 만약 함수가 first class value라면 functional language라고 부른다.

-> C언어 등 대부분의 언어에서 함수를 매개변수로 주거나, 리턴할 수는 없다. 그러나 함수형 언어에서는 함수를 인자로 넘겨주거나 리턴할 수 있다.



2) 이름 없는 함수 (Nameless Functions)

이름없는 함수 정의: fun [param_list] -> [expression]

๏ param_list : 파라미터 리스트
๏ Expression : 함수 Body의 내용

이름없는 함수 호출: [function][arg_list]



3) 이름이 있는 함수 (Named Functions)

이름있는 함수 정의: let [id][param_list] = [expression]

๏ id : 함수 이름
๏ param_list : 파라미터 리스트
๏ Expression : 함수 Body의 내용

이름있는 함수 호출: let [id][param_list] = [expression1] in [expression2]

๏ expression2 : 함수를 실행하는 expression



4) 함수의 종류(type)

type1 -> type2

함수 타입은 화살표로 표시된다.

๏ type1 : 파라미터 타입
๏ type2 : 함수 Body의 타입

파라미터가 여러개인 경우 curried form이 사용된다.

curried form : f(x,y,z) => f(x)(y)(z)

๏ f: int x int x int -> int => f: int -> int -> int -> int

let inc x = x+1 // int type을 받아서 int 리턴
// inc : int -> int 

let sum x y = x+y // sum: int -> int -> int 

let sum x y = x + y in 
let sum' = sum 1 in  // sum' : int -> int
// sum은 인수 2개인데 한개만 받음 -> partial evaluation이다. 한 개 먼저 일부 실행하여 sum'에 저장한다.
let res = sum 3 in // res : int 
// 두번째 인자 넘겨줌
Format.printf "Result: %d\n" res


5) High order function

함수를 인자로 받거나 리턴하는 함수

app 은 f x를 인자로 받는데, f가 함수이기 때문에 함수를 인자로 받는 high order function 이다.

sum은 x를 인자로 받아서, 함수를 리턴하는 함수이다. 리턴하는 함수는 int를 받아서 int를 리턴하는 함수이다.



6) 재귀함수 (Recursive function)

named function으로 rec 키워드를 이용하면 재귀함수를 정의할 수 있다.
rec 키워드가 없다면 에러가 발생한다.



5. 튜플

순서가 있는 값들의 컬렉션

각 값은 타입이 다를 수 있다.
파이썬의 튜플과 동일하다.

튜플의 타입은 별표시로 표시된다. ➡ type type
ex. (1, “hi”) : int
string

Let or let-in을 이용해서 튜플 요소를 각 변수에 바인딩시킬 수 있다.
➡ let x, y = (1,3) or let x,y = (1,3) in x + y ➡ x가 1에 binding 되고 y가 3에 바인딩된다.



6. 조건문 (Conditional Expressions)

If be then e1 else e2

만약 be가 참이면, e1의 결과값이 전체 리턴값이 되고 아니면 e2의 결과값이 전체 리턴값이 된다.
e1과 e2의 타입은 동일해야 한다.
조건문의 조건식은 boolean 값만 올 수 있다.

๏ if 2 > 1 then 0 else 1;;
➡ : int = 0
๏ If 2 < 1 then 0 else 1;;
➡ : int = 1



7. 타입 추론

c, java에서는 타입을 반드시 명시해주어야 한다.

public static int f(int n)
{
	int a = 2;
	return a * n;
}

ocaml은 타입을 명시하지 않아도 된다.

 let f n =
 	let a = 2 in
 		a * n;;
// type 추론 =  val f : int -> int = <fun>

f 함수는 int를 받아서 int를 반환하는 함수라는 것을 추론한다.

🔔 Ocaml에서 타입 추론 절차

let sum_if_true test first second =
  (if test first then first else 0)
  + (if test second then second else 0);;
  val sum_if_true : (int -> bool) -> int -> int -> int = <fun>

1) first와 second의 type은 int여야 한다. 왜냐하면 조건문의 branch는 같은 타입이어야 하기 때문이다.
2) test의 type은 함수일 것이다. test가 함수를 call 하는 것처럼 사용되었기 때문에 a->b 함수 타입이다.
3) test함수의 리턴값 (b)는 불리언 타입일 것이다. 조건문의 조건식으로 사용되었기 때문이다.
4) test함수의 인자값 (a)는 int일 것이다.
5) val sum_if_true : (int -> bool) -> int -> int -> int = <fun>

타입을 명시적으로 지정해주는 것도 가능하다.

 let sum_if_true (test : int -> bool) (x : int) (y : int) : int =
 (if test x then x else 0) + (if test y then y else 0);;
 val sum_if_true : (int -> bool) -> int -> int -> int = <fun>

만약 명시적으로 지정한 것이 틀리면 ocaml은 찾아내서 에러를 리포트한다.

  let sum_if_true (test : int -> int) (x : int) (y : int) : int =
  (if test x then x else 0) + (if test y then y else 0);;
// Error: The expression (test x) has type int but an expressionwas expected of type bool;

0개의 댓글