무냐의 개발일지

[OSSU] <Programming Language, Part A> / Week3 본문

OSSU_CS coursework

[OSSU] <Programming Language, Part A> / Week3

무냐코드 2024. 5. 23. 23:32

 

순서는 상관없다. 어차피 매칭된 key의 값들이 있는거니까

값이 많아질수록 tuples(position으로 접근)보다는 records(name으로 접근) 형식으로 쓰는게 당연히 기억하지 않아도 되고 편하겠지

 

 

 

 

mytype은 이 타입들 중 하나이다

 

 

 

 

 

| Pattern Matching

datatype mytype = TwoInts of int * int 
                | Str of string 
                | Pizza

fun f x = 
    case x of 
	Pizza => 3 
      | Str s => 8
      | TwoInts(i1,i2) => i1 + i2

(*    | Pizza => 4; (* redundant case: error *) *)
(*fun g x = case x of Pizza => 3 (* missing cases: warning *) *)

f Pizza;
f (Str "hi");
f (Str "whatup");
f (TwoInts(3,4));
f (TwoInts(50,5));


#결과
- 
val it = 3 : int
val it = 8 : int
val it = 8 : int
val it = 7 : int
val it = 55 : int
-

 

 

| 중복 불가

 

 

 

option으로 들어간다?? 이름은 일단 무조건 있어야하고, ID랑 미들네임은 있어도 없어도 되는거니까 option으로 넣는다

 

 

| Type Synonyms

 

 

 

 

| Lists and Options are Datatypes

sum_list xs : xs 리스트 안에 있는 모든 숫자를 합치겠다

 

append(xs, ys) : xs를 ys리스트에 붙이겠다

 

| Pattern Matching

 

ML에서 함수는 실제로 오직 1개만의 변수를 갖는다. 그걸 가지고 함수 본문이 pattern matching을 통해, 튜플의 1번째, 2번째... n번째에 대해 어떤 작업을 할지 작동하는 것임!! 

 

 

| Type Inference

주어진 변수 내에서 몇 개만 사용한다고 했을 때, 함수 본문에 사용되지 않는 변수는 int 같은 타입이 아니라, 좀 더 general한 타입인 'a 이런 식으로 표현이 된다. 괜찮다. 

 

 

| 그렇다면 뭐가 더 General 한 타입이지??

polymorphic type is more general 

 

 

| Nested Patterns

 

ZIP

(* do this *)
fun zip3 list_triple =
    case list_triple of 
	([],[],[]) => []
      | (hd1::tl1,hd2::tl2,hd3::tl3) => (hd1,hd2,hd3)::zip3(tl1,tl2,tl3)
      | _ => raise ListLengthMismatch
(* _ means else. if not matches none of above cases, then _ *)

 

 

UNZIP

(* and the inverse *)
fun unzip3 lst =
    case lst of
	[] => ([],[],[])
      | (a,b,c)::tl => let val (l1,l2,l3) = unzip3 tl
		       in
			   (a::l1,b::l2,c::l3)
		       end

 

 

More of Nested Patterns

(* another elegant use of "deep" patterns *)
fun nondecreasing xs =
    case xs of
	[] => true
      | x::[] => true
      | head::(neck::rest) => (head <= neck andalso nondecreasing (neck::rest))

 

x 대신 _ 를 쓰는게 더 세련됐다. 특정 변수가 아니라, 그냥 '뭐라도 있으면' 이라는 뜻임! 

 

 

datatype sgn = P | N | Z

fun multsign (x1,x2) = 
  let fun sign x = if x=0 then Z else if x>0 then P else N 
  in
      case (sign x1,sign x2) of
	  (Z,_) => Z
	| (_,Z) => Z
	| (P,P) => P
	| (N,N) => P
	| _     => N (* many say bad style; I am okay with it --> (N,P), (P,N) => N *)
  end

(* simpler use of wildcard pattern for when you do not need the data *)

 

요런식으로 안에 nested 형태로 쓰면 훨씬 간결하고 깔끔해진다

 

fun len xs =
    case xs of
       [] => 0
      | _::xs' => 1 + len xs'

 

 

| Pattern Matching

 

 

 

| Exceptions

 

raise : 예외를 발생시킨다. 값을 데려오지 않는다 .

 

 

| Tail Recursion

Simple version

이거는 fact를 부를때마다 앞에 n을 곱해주는 추가작업을 해주지만

 

이거는 그냥 aux(n-1, acc*n) 자체를 부르고 다른 추가작업은 안해준다. 이게 더 효율적이라고 한다.

스택을 따로 만드는게 아니라, fact 프레임을 aux 프레임으로 바꾸고, 이대로 쭉 가서 끝나는거다. aux(0,6)을 반환하면 즉시 답을 얻는다.