Functions

함수

HNU CE 프로그래밍언어론 (2021년 1학기)

실행환경에 영향을 주는 언어 요소

프로그램의 특정 범위에 한정된 변수 활용

유효범위(scope)가 있는 변수 선언

  • 지역변수 선언
  • 함수 파라미터(형식인자)
  • ...

let식

\begin{array}{l} e ::= x \mid n \mid b \mid e + e \mid e \land e \mid \neg e \mid e = e \mid e \lt e \\~\quad~~ \mid \texttt{if}\;e\;\texttt{then}\;e\;\texttt{else}\;e\; \mid \texttt{let}\;x=e\;\texttt{in}\;e\; \end{array}

Semantics

~\sigma,e \Downarrow v~
v \in \texttt{Value} \;=\; \texttt{Int} \uplus \texttt{Bool}
e \in \texttt{Expr} \quad n\in\texttt{Int} \quad b\in\texttt{Bool}

Syntax

\displaystyle\frac{\sigma,\,e\,\Downarrow\,v \quad [x\mapsto v]\sigma,\,e_1\,\Downarrow\,v_1 }{ \sigma,\,\texttt{let}\;x=e\;\texttt{in}\;e_1 \;\Downarrow\; v_1}
\sigma' = [x\mapsto v]\sigma
\begin{array}{l} \sigma'(x) = v \\ \sigma'(y) = \sigma(y) \quad (y\neq x) \end{array}

함수 문법

\begin{array}{l} e ::= x \mid n \mid b \mid e + e \mid e \land e \mid \neg e \mid e = e \mid e \lt e \\~\quad~~ \mid \texttt{if}\;e\;\texttt{then}\;e\;\texttt{else}\;e\; \mid \texttt{let}\;x=e\;\texttt{in}\;e\; \\~\quad~~ \mid \lambda x.e \quad{\color{red}_\textit{함수 정의}} \\~\quad~~ \mid e~e \quad{\color{red}_\textit{함수 호출(적용)}} \end{array}

Semantics

~\sigma,e \Downarrow v~
v \in \texttt{Value} \,=\, \texttt{Int} \uplus \texttt{Bool} \uplus {\color{red}???}
e \in \texttt{Expr} \quad n\in\texttt{Int} \quad b\in\texttt{Bool}

Syntax

함수의 정의와 호출(적용) 사례

\sigma,\,\lambda x.\,x+1 ~~\Downarrow~~ {\color{red}\text{함수값}}
f(x) = x + 1
\sigma,\,(\lambda x.\,x+1)~3 ~~\Downarrow~~ 4
\sigma,\, \texttt{let}\;f=(\lambda x.\,x+1)\;\texttt{in}\;f~3 ~~\Downarrow~~ 4

함수 의미규칙

\begin{array}{l} e ::= x \mid n \mid b \mid e + e \mid e \land e \mid \neg e \mid e = e \mid e \lt e \\~\quad~~ \mid \texttt{if}\;e\;\texttt{then}\;e\;\texttt{else}\;e\; \mid \texttt{let}\;x=e\;\texttt{in}\;e\; \\~\quad~~ \mid \lambda x.e \mid e~e \end{array}

Semantics

~\sigma,e \Downarrow v~
v \in \texttt{Value} \,=\, \texttt{Int} \uplus \texttt{Bool} \uplus \texttt{Clos}
e \in \texttt{Expr} \quad n\in\texttt{Int} \quad b\in\texttt{Bool}

Syntax

\texttt{Env} = \texttt{Name}\xrightarrow{_\textrm{fin}}\texttt{Value}
\frac{}{\sigma,\,\lambda x.e ~~\Downarrow~~ \langle\sigma,\lambda x.e\rangle}
\frac{ \sigma,\,e_1\,\Downarrow\,\langle\sigma_1,\lambda x.e\rangle \quad \sigma,\,e_2\,\Downarrow\,v_2 \quad [x\mapsto v_2]\sigma_1,\,e\,\Downarrow\,v}{ \sigma,\,e_1\;e_2 ~\Downarrow~ v}
\langle \sigma, \lambda x.e \rangle \in \texttt{Clos} ~ \subset ~ \texttt{Env} \times \texttt{Expr}

클로저(closure)

Static scope

Lexical scope

클로저 없이 함수를 처리한다면?

\begin{array}{l} e ::= x \mid n \mid b \mid e + e \mid e \land e \mid \neg e \mid e = e \mid e \lt e \\~\quad~~ \mid \texttt{if}\;e\;\texttt{then}\;e\;\texttt{else}\;e\; \mid \texttt{let}\;x=e\;\texttt{in}\;e\; \\~\quad~~ \mid \lambda x.e \mid e~e \end{array}

Semantics

~\sigma,e \Downarrow v~
v \in \texttt{Value} \,=\, \texttt{Int} \uplus \texttt{Bool} \uplus \texttt{Fun}
e \in \texttt{Expr} \quad n\in\texttt{Int} \quad b\in\texttt{Bool}

Syntax

\frac{}{\sigma,\,\lambda x.e ~~\Downarrow~~ \lambda x.e}
\frac{ \sigma,\,e_1\,\Downarrow\,\lambda x.e \quad \sigma,\,e_2\,\Downarrow\,v_2 \quad [x\mapsto v_2]\sigma,\,e\,\Downarrow\,v}{ \sigma,\,e_1\;e_2 ~\Downarrow~ v}
\lambda x.e \in \texttt{Fun} ~ \subset \texttt{Expr}

함수 코드만으로 ...

간단해서 구현하긴 편하겠는데 ...

이래도 정말 괜찮은건가???

Dynamic scope

Dynamic scope

let z = 1      
in
let f = \x.x+z 
in
let y1 = f 10
in
let z = 2
in
let y2 = f 10
in
let z = 3
in
let y3 = f 10
in
print(y1,y2,y3)

Static scope

\sigma_1 = \{z\mapsto 1\}
\sigma_1 = \{z\mapsto 1\}
\sigma_2 =\! \left\{\!\!\!\begin{array}{l} f\mapsto\langle\sigma_1,\lambda x.x+z\rangle,\\ z\mapsto 1 \end{array}\!\!\!\right\}
\sigma_2 =\! \left\{\!\!\!\begin{array}{l} f\mapsto\lambda x.x+z,\\ z\mapsto 1 \end{array}\!\!\!\right\}
\sigma_3 = \{\cdots,y_1\mapsto 11,\cdots\}
\sigma_5 = \{\cdots, y_2\mapsto 11,\cdots\}
\sigma_7 = \{\cdots, y_3\mapsto 11,\cdots\}
\sigma_4 =\! \left\{\!\!\!\begin{array}{l} f\mapsto\langle\sigma_1,\lambda x.x+z\rangle,\\ z\mapsto 2,\cdots \end{array}\!\!\!\right\}
\sigma_6 =\! \left\{\!\!\!\begin{array}{l} f\mapsto\langle\sigma_1,\lambda x.x+z\rangle,\\ z\mapsto 3,\cdots \end{array}\!\!\!\right\}
\sigma_4 =\! \left\{\!\!\!\begin{array}{l} f\mapsto\lambda x.x+z,\\ z\mapsto 2,\cdots \end{array}\!\!\!\right\}
\sigma_3 = \{\cdots,y_1\mapsto 11,\cdots\}
\sigma_5 = \{\cdots, y_2\mapsto 12,\cdots\}
\sigma_6 =\! \left\{\!\!\!\begin{array}{l} f\mapsto\lambda x.x+z,\\ z\mapsto 3,\cdots \end{array}\!\!\!\right\}
\sigma_7 = \{\cdots, y_3\mapsto 13,\cdots\}
11,11,11
11,12,13
int n = 100; // 전역변수 n

void print_global_n() { printf("%d\n", n); }

void f() {
    int n = 200; // 함수 f의 지역변수 n
    print_global_n();
}

void g() {
    int n = 300; // 함수 g의 지역변수 n
    print_global_n();
}

int main() {
    print_global_n(); // 100 출력
    f(); // static scope면 100, dynamic scope면 200 출력
    g(); // static scope면 100, dynamic scope면 300 출력
	return 0;
}

Dynamic scope

  • 고급 프로그래밍 언어들을 개발하던 초창기에 구현을 편하게 하려다 보니 생긴 역사적 실수
  • 사실상 유일하게 변수 유효범위를 처리하는 정상적인 방법은 Static scope
  • 프로그래밍언어의 특정 기능을 구현하기 위한 내부적인 매커니즘으로 Dynamic scope를 활용할 여지는 있지만 언어의 전반적인 유효범위 처리 방식으론 절대 바람직하지 않다 
  • Dynamic scope가 유연하다 어쩌다 장점이 있다고 주장하기도 했었는데 ...
int n = 100; // 전역변수 n

void print_number(int n) { printf("%d\n", n); }

void f() {
    int n = 200; // 함수 f의 지역변수 n
    print_number(n);
}

void g() {
    int n = 300; // 함수 g의 지역변수 n
    print_number(n);
}

int main() {
    print_number(n); // 100 출력
    f();             // 200 출력
    g();             // 300 출력
	return 0;
}

재귀함수로 반복적 계산

  • 대부분의 프로그래밍언어에서 반복적 계산을 위한 요소(반복문, 재귀함수 등)을 직접적으로 제공
     
  • 반복적 계산을 위한 요소가 직접 제공되지 않더라도도 람다식이 있으면 재귀함수 만들어 쓰는 것이 가능 

Fixpoint Combinator

\texttt{fix}~g = g\;(\texttt{fix}~g)
\text{이 조건을 만족하는 \texttt{fix}를 람다식으로 작성 가능}
Z = \lambda f.(\lambda x.\,f(\lambda v.\,x\,x\,v))~(\lambda x.\,f(\lambda v.\,x\,x\,v))
\begin{array}{rl} Z\,g\!\!\!\! &= (\lambda x.\,g~(\lambda v.\,x\,x\,v))~(\lambda x.\,g~(\lambda v.\,x\,x\,v))\\ &= g~(\lambda v.\,(\lambda x.\,g~(\lambda v.\,x\,x\,v))\,(\lambda x.\,g~(\lambda v.\,x\,x\,v))\,v)\\ &= g~(\lambda v.\,(Z\,g)~v)\\ &= g~(Z\,g) \end{array}
Z = (\f.(\x.f(\v.x x v)) (\x.f(\v.x x v)))
g = (\f.\x.if x>0 then x + f (x-1) else 0)

  Z g 3 
= (\x.g(\v.x x v)) (\x.g(\v.x x v)) 3
= g (\v.(\x.g(\v.x x v)) (\x.g(\v.x x v)) v) 3
= (\x.if x>0 then x + (\v.(\x.g(\v.x x v)) (\x.g(\v.x x v)) v) (x-1) else 0) 3
= if 3>0 then 3 + (\v.(\x.g(\v.x x v)) (\x.g(\v.x x v)) v) (3-1) else 0
= 3 + (\v.(\x.g(\v.x x v)) (\x.g(\v.x x v)) v) 2
= 3 + (\x.g(\v.x x v)) (\x.g(\v.x x v)) 2
= 3 + g (\v.(\x.g(\v.x x v)) (\x.g(\v.x x v)) v) 2
= 3 + (\x.if x>0 then x + (\v.(\x.g(\v.x x v)) (\x.g(\v.x x v)) v) (x-1) else 0) 2
= 3 + if 2>0 then 2 + (\v.(\x.g(\v.x x v)) (\x.g(\v.x x v)) v) (2-1) else 0
= 3 + 2 + (\v.(\x.g(\v.x x v)) (\x.g(\v.x x v)) v) 1
= 3 + 2 + (\x.g(\v.x x v)) (\x.g(\v.x x v)) 1
= 3 + 2 + g (\v.(\x.g(\v.x x v)) (\x.g(\v.x x v)) v) 1
= 3 + 2 + (\x.if x>0 then x + (\v.(\x.g(\v.x x v)) (\x.g(\v.x x v)) v) (x-1) else 0) 1
= 3 + 2 + if 1>0 then 1 + (\v.(\x.g(\v.x x v)) (\x.g(\v.x x v)) v) (1-1) else 0
= 3 + 2 + 1 + (\v.(\x.g(\v.x x v)) (\x.g(\v.x x v)) v) 0
= 3 + 2 + 1 + (\x.g(\v.x x v)) (\x.g(\v.x x v)) 0
= 3 + 2 + 1 + g (\v.(\x.g(\v.x x v)) (\x.g(\v.x x v)) v) 0
= 3 + 2 + 1 + (\x.if x>0 then x + (\v.(\x.g(\v.x x v)) (\x.g(\v.x x v)) v) (x-1) else 0) 0
= 3 + 2 + 1 + if 0>0 then 0 + (\v.(\x.g(\v.x x v)) (\x.g(\v.x x v)) v) (0-1) else 0
= 3 + 2 + 1 + 0
= 6

함수

By 안기영 (Ahn, Ki Yung)

함수

HNU CE 프로그래밍언어론 (2021년 1학기)

  • 828