Programming Languages 모듈과펑터 2016 년봄학기 손시운 (ssw5176@kangwon.ac.kr) 담당교수 : 임현승교수님
모듈 (module) 관련있는정의 ( 변수또는함수 ) 를하나로묶은패키지 예약어 module과 struct end를사용하여정의 아래는모듈의예시 ( 우선순위큐, priority queue) # module PrioQueue = struct type priority = int type 'a queue = Empty Node of priority * 'a * 'a queue * 'a queue let empty = Empty let rec insert queue prio elt = match queue with Empty -> Node(prio, elt, Empty, Empty) ( 중략 ) else Node(rprio, relt, left, remove_top right) let extract = function Empty -> raise Queue_is_empty Node(prio, elt, _, _) as queue -> (prio, elt, remove_top queue) end;; 2016-05-11 2
기본사용법 (1/2) 이미우리는모듈을사용함 라이브러리를통해 List 및 Pervasives 모듈을사용 # String.length "Hello, world!" ;; - : int = 13 # String.length "Programming Languages";; - : int = 21 파일을통해모듈생성 amodule.ml 과같이프로그램을작성하면, Amodule 이라는모듈이자동생성 아래와같이컴파일하여라이브러리생성 [cs08293@cs1 test]$ cat amodule.ml let hello () = print_endline "Hello" [cs08293@cs1 test]$ ocamlc -c amodule.ml [cs08293@cs1 test]$ ocamlc -a amodule.cmo -o library [cs08293@cs1 test]$ ocaml OCaml version 4.01.0 # #load "library" ;; # Amodule.hello () ;; Hello - : unit = () 2016-05-11 3
기본사용법 (2/2) 자주사용하는모듈은키워드 open 을사용하여바로접근 # open String;; # length "Hello, world!" ;; - : int = 13 # length "Programming Languages" ;; - : int = 21 구분이모호한이름의내용을갖는모듈은 open 을사용하지않음 # open Printf let my_data = [ "a"; "beautiful"; "day" ] let () = List.iter (fun s -> printf "%s\n" s) my_data ;; a beautiful day val my_data : string list = ["a"; "beautiful"; "day"] 2016-05-11 4
시그너쳐 (Signatures) (1/2) 모듈은특별한지정이없다면외부에서모든것이접근가능 하지만필요한것만외부에제공할필요가있음 예를들어아래의모듈에서 message 값은다른모듈이접근할필요가없음 시그너쳐 let message = "Hello" let hello () = print_endline message 모듈의구현을가려줄수있는모듈인터페이스 모듈이.ml 파일에정의되는것처럼, 시그너쳐는.mli 파일에작성 이파일은타입이명시된값 (value) 등을저장 2016-05-11 5
시그너쳐 (Signatures) (2/2) 시그너쳐생성 amodule.ml 과 amodule.mli 파일을다음과같이생성 [cs08293@cs1 test]$ cat amodule.ml let message = "Hello" let hello () = print_endline message [cs08293@cs1 test]$ cat amodule.mli val hello : unit -> unit Top-level 에서접근확인 [cs08293@cs1 test]$ ocamlc -c amodule.mli [cs08293@cs1 test]$ ocamlc -c amodule.ml [cs08293@cs1 test]$ ocamlc -a amodule.cmo -o library [cs08293@cs1 test]$ ocaml OCaml version 4.01.0 # #load "library" ;; # Amodule.hello () ;; Hello - : unit = () # Amodule.message ;; Characters 0-15: Amodule.message ;; ^^^^^^^^^^^^^^^ Error: Unbound value Amodule.message 2016-05-11 6
펑터 (functor) (1/3) 다른모듈에의해매개화되는 (parametrized) 모듈 함수가인수 (arguments) 라는다른값 (value) 으로매개화되는것과유사 e.g. 길이가 n인배열에대해서만동작하는배열연산들의콜렉션을돌려주는펑터 길이가 n이아닌배열을넘긴다면컴파일에러가발생 펑터를사용하지않을경우, 훨씬더나쁜결과로런타임에러를야기할것 펑터사용법 (1/2) Set 모듈에는 Make 펑터를제공함 이펑터는 ( 최소한 ) 요소의타입과 compare 함수를제공하는모듈인자를요구 이어서 2016-05-11 7
펑터 (functor) (2/3) 펑터사용법 (2/2) 정수의집합 # module Int_set = Set.Make (struct type t = int let compare = compare end) ;; module Int_set : sig type elt = int type t val empty : t val is_empty : t -> bool val mem : elt -> t -> bool val add : elt -> t -> t val singleton : elt -> t ( 중략 ) val elements : t -> elt list val min_elt : t -> elt val max_elt : t -> elt val choose : t -> elt val split : elt -> t -> t * bool * t val find : elt -> t -> elt end # let s = Int_set.empty ;; val s : Int_set.t = <abstr> # let t = Int_set.add 1 s ;; val t : Int_set.t = <abstr> # let u = Int_set.add 2 s ;; val u : Int_set.t = <abstr> # let tu = Int_set.union t u ;; val tu : Int_set.t = <abstr> # Int_set.find 1 tu ;; - : Int_set.elt = 1 # Int_set.find 2 tu ;; - : Int_set.elt = 2 # Int_set.find 3 tu ;; Exception: Not_found. 2016-05-11 8
펑터 (functor) (3/3) 펑터를정의하는방법 하나의인자를가진펑터는다음과같이정의 module F (X : X_type) = struct... end X 는인자로넘겨질모듈 X_type 는이모듈의시그너쳐 펑터는프로그래머가정확한프로그램을작성하는것을돕기위한것 2016-05-11 9
간단한펑터만들기 (1/4) 정렬된집합을만드는모듈을반환하는펑터생성 (1/2) 모듈에는다음 2 개의함수를포함 원소 (element) 를추가하는함수 ( 추가할때주어진 compare 함수를사용하여정렬 ) 집합에원소의유무를판별하는함수 비교결과에대한타입정의 # type comparison = Less Equal Greater;; type comparison = Less Equal Greater 펑터의인자모듈에대한시그너쳐정의 # module type ORDERED_TYPE = sig type t val compare: t -> t -> comparison end;; module type ORDERED_TYPE = sig type t val compare : t -> t -> comparison end 2016-05-11 10
간단한펑터만들기 (2/4) 정렬된집합을만드는모듈을반환하는펑터생성 (2/2) 펑터정의 # module Set = functor (Elt: ORDERED_TYPE) -> struct type element = Elt.t let empty = [] let rec add x s = match s with [] -> [x] hd::tl -> match Elt.compare x hd with Equal -> s Less -> x :: s Greater -> hd :: add x tl let rec member x s = match s with [] -> false hd::tl -> match Elt.compare x hd with Equal -> true Less -> false Greater -> member x tl end;; 2016-05-11 11
간단한펑터만들기 (3/4) 앞의펑터를사용하여모듈생성 (1/2) 펑터에사용할인자모듈정의 # module OrderedString = struct type t = string let compare x y = if x = y then Equal else if x < y then Less else Greater end;; module OrderedString : sig type t = string val compare : 'a -> 'a -> comparison end 모듈생성 # module StringSet = Set(OrderedString);; module StringSet : sig type element = OrderedString.t val empty : 'a list val add : OrderedString.t -> OrderedString.t list -> OrderedString.t list val member : OrderedString.t -> OrderedString.t list -> bool end 2016-05-11 12
간단한펑터만들기 (4/4) 앞에서정의한펑터를사용하여모듈생성 (2/2) 모듈을사용하여집합생성 # StringSet.member "bar" (StringSet.add "foo" StringSet.empty);; - : bool = false 앞의펑터를통해, IntSet 을만들고다음을테스트해보세요. # IntSet.member 2 (IntSet.add 2 (IntSet.add 1 IntSet.empty));; - : bool = true 2016-05-11 13