Functions
함수
HNU CE 프로그래밍언어론 (2021년 1학기)
실행환경에 영향을 주는 언어 요소
프로그램의 특정 범위에 한정된 변수 활용
즉 유효범위(scope)가 있는 변수 선언
- 지역변수 선언
- 함수 파라미터(형식인자)
- ...
let식
e::=x∣n∣b∣e+e∣e∧e∣¬e∣e=e∣e<e ∣ifetheneelsee∣letx=eine
\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
σ,e⇓v
~\sigma,e \Downarrow v~
v∈Value=Int⊎Bool
v \in \texttt{Value} \;=\; \texttt{Int} \uplus \texttt{Bool}
e∈Exprn∈Intb∈Bool
e \in \texttt{Expr} \quad n\in\texttt{Int} \quad b\in\texttt{Bool}
Syntax
σ,letx=eine1⇓v1σ,e⇓v[x↦v]σ,e1⇓v1
\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}
σ′=[x↦v]σ
\sigma' = [x\mapsto v]\sigma
σ′(x)=vσ′(y)=σ(y)(y=x)
\begin{array}{l}
\sigma'(x) = v \\
\sigma'(y) = \sigma(y) \quad (y\neq x)
\end{array}
함수 문법
e::=x∣n∣b∣e+e∣e∧e∣¬e∣e=e∣e<e ∣ifetheneelsee∣letx=eine ∣λx.e함수 정의 ∣e e함수 호출(적용)
\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
σ,e⇓v
~\sigma,e \Downarrow v~
v∈Value=Int⊎Bool⊎???
v \in \texttt{Value} \,=\, \texttt{Int} \uplus \texttt{Bool} \uplus {\color{red}???}
e∈Exprn∈Intb∈Bool
e \in \texttt{Expr} \quad n\in\texttt{Int} \quad b\in\texttt{Bool}
Syntax
함수의 정의와 호출(적용) 사례
σ,λx.x+1 ⇓ 함수값
\sigma,\,\lambda x.\,x+1 ~~\Downarrow~~ {\color{red}\text{함수값}}
f(x)=x+1
f(x) = x + 1
σ,(λx.x+1) 3 ⇓ 4
\sigma,\,(\lambda x.\,x+1)~3 ~~\Downarrow~~ 4
σ,letf=(λx.x+1)inf 3 ⇓ 4
\sigma,\, \texttt{let}\;f=(\lambda x.\,x+1)\;\texttt{in}\;f~3 ~~\Downarrow~~ 4
함수 의미규칙
e::=x∣n∣b∣e+e∣e∧e∣¬e∣e=e∣e<e ∣ifetheneelsee∣letx=eine ∣λx.e∣e e
\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
σ,e⇓v
~\sigma,e \Downarrow v~
v∈Value=Int⊎Bool⊎Clos
v \in \texttt{Value} \,=\, \texttt{Int} \uplus \texttt{Bool} \uplus \texttt{Clos}
e∈Exprn∈Intb∈Bool
e \in \texttt{Expr} \quad n\in\texttt{Int} \quad b\in\texttt{Bool}
Syntax
Env=NamefinValue
\texttt{Env} = \texttt{Name}\xrightarrow{_\textrm{fin}}\texttt{Value}
σ,λx.e ⇓ ⟨σ,λx.e⟩
\frac{}{\sigma,\,\lambda x.e ~~\Downarrow~~ \langle\sigma,\lambda x.e\rangle}
σ,e1e2 ⇓ vσ,e1⇓⟨σ1,λx.e⟩σ,e2⇓v2[x↦v2]σ1,e⇓v
\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}
⟨σ,λx.e⟩∈Clos ⊂ Env×Expr
\langle \sigma, \lambda x.e \rangle \in \texttt{Clos} ~ \subset ~ \texttt{Env} \times \texttt{Expr}
클로저(closure)
Static scope
Lexical scope
클로저 없이 함수를 처리한다면?
e::=x∣n∣b∣e+e∣e∧e∣¬e∣e=e∣e<e ∣ifetheneelsee∣letx=eine ∣λx.e∣e e
\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
σ,e⇓v
~\sigma,e \Downarrow v~
v∈Value=Int⊎Bool⊎Fun
v \in \texttt{Value} \,=\, \texttt{Int} \uplus \texttt{Bool} \uplus \texttt{Fun}
e∈Exprn∈Intb∈Bool
e \in \texttt{Expr} \quad n\in\texttt{Int} \quad b\in\texttt{Bool}
Syntax
σ,λx.e ⇓ λx.e
\frac{}{\sigma,\,\lambda x.e ~~\Downarrow~~ \lambda x.e}
σ,e1e2 ⇓ vσ,e1⇓λx.eσ,e2⇓v2[x↦v2]σ,e⇓v
\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}
λx.e∈Fun ⊂Expr
\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
σ1={z↦1}
\sigma_1 = \{z\mapsto 1\}
σ1={z↦1}
\sigma_1 = \{z\mapsto 1\}
σ2={f↦⟨σ1,λx.x+z⟩,z↦1}
\sigma_2 =\!
\left\{\!\!\!\begin{array}{l}
f\mapsto\langle\sigma_1,\lambda x.x+z\rangle,\\
z\mapsto 1
\end{array}\!\!\!\right\}
σ2={f↦λx.x+z,z↦1}
\sigma_2 =\!
\left\{\!\!\!\begin{array}{l}
f\mapsto\lambda x.x+z,\\
z\mapsto 1
\end{array}\!\!\!\right\}
σ3={⋯,y1↦11,⋯}
\sigma_3 = \{\cdots,y_1\mapsto 11,\cdots\}
σ5={⋯,y2↦11,⋯}
\sigma_5 = \{\cdots, y_2\mapsto 11,\cdots\}
σ7={⋯,y3↦11,⋯}
\sigma_7 = \{\cdots, y_3\mapsto 11,\cdots\}
σ4={f↦⟨σ1,λx.x+z⟩,z↦2,⋯}
\sigma_4 =\!
\left\{\!\!\!\begin{array}{l}
f\mapsto\langle\sigma_1,\lambda x.x+z\rangle,\\
z\mapsto 2,\cdots
\end{array}\!\!\!\right\}
σ6={f↦⟨σ1,λx.x+z⟩,z↦3,⋯}
\sigma_6 =\!
\left\{\!\!\!\begin{array}{l}
f\mapsto\langle\sigma_1,\lambda x.x+z\rangle,\\
z\mapsto 3,\cdots
\end{array}\!\!\!\right\}
σ4={f↦λx.x+z,z↦2,⋯}
\sigma_4 =\!
\left\{\!\!\!\begin{array}{l}
f\mapsto\lambda x.x+z,\\
z\mapsto 2,\cdots
\end{array}\!\!\!\right\}
σ3={⋯,y1↦11,⋯}
\sigma_3 = \{\cdots,y_1\mapsto 11,\cdots\}
σ5={⋯,y2↦12,⋯}
\sigma_5 = \{\cdots, y_2\mapsto 12,\cdots\}
σ6={f↦λx.x+z,z↦3,⋯}
\sigma_6 =\!
\left\{\!\!\!\begin{array}{l}
f\mapsto\lambda x.x+z,\\
z\mapsto 3,\cdots
\end{array}\!\!\!\right\}
σ7={⋯,y3↦13,⋯}
\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
fix g=g(fix g)
\texttt{fix}~g = g\;(\texttt{fix}~g)
이 조건을 만족하는 fix를 람다식으로 작성 가능
\text{이 조건을 만족하는 \texttt{fix}를 람다식으로 작성 가능}
Z=λf.(λx.f(λv.xxv)) (λx.f(λv.xxv))
Z = \lambda f.(\lambda x.\,f(\lambda v.\,x\,x\,v))~(\lambda x.\,f(\lambda v.\,x\,x\,v))
Zg=(λx.g (λv.xxv)) (λx.g (λv.xxv))=g (λv.(λx.g (λv.xxv))(λx.g (λv.xxv))v)=g (λv.(Zg) v)=g (Zg)
\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
Functions 함수 HNU CE 프로그래밍언어론 (2021년 1학기)
함수
By 안기영 (Ahn, Ki Yung)
함수
HNU CE 프로그래밍언어론 (2021년 1학기)
- 993