C# Lambda-Expression | ๋๋ค์
๐ซ Q
- ๋๋ค์ ?
- ๋๋ค์์ ์ ์ธํ๊ณ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
- ๋ฌธ ํ์์ ๋๋ค์์ ์์ฑํ๊ณ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
- ์ ํธ๋ฆฌ
๐ซ Lambda-Expression | ๋๋ค์
์ต๋ช
-๋ฉ์๋
๋ฅผ ๋ง๋๋ ๋ ํ๋์ ๋ฐฉ๋ฒ.
๋๋ค์์ผ๋ก ๋ง๋๋ ์ต๋ช
๋ฉ์๋๋ ๋ฌด๋ช
-ํจ์(Anonymous Function)
๋ผ๋ ์ด๋ฆ์ผ๋ก ๋ถ๋ฅธ๋ค.
๐ซง Lambda-Expression ๊ตฌํ
(๋งค๊ฐ๋ณ์) => ์
๊ฐ์ ๋ชจ์์ผ๋ก ๋ง๋ ๋ค.
=>
๋ ์
๋ ฅ ์ฐ์ฐ์
(ํน์ ๋๋ค ์ฐ์ฐ์(Lambda Operator)).
=>
๋ฅผ ์ค์ฌ์ผ๋ก ์ผ์ชฝ์๋ ๋งค๊ฐ๋ณ์, ์ค๋ฅธ์ชฝ์๋ ์์ด ์์น.
๊ทธ์ ์ผ์ชฝ ๋งค๊ฐ ๋ณ์๋ฅผ ์ค๋ฅธ์ชฝ ์์ ์ ๋ฌํ๋ ์ญํ .
1
(int x, int y) => x + y
๐ซง Type-Inference | ํ์ ์ถ๋ก (ํ์ ์ ์ถ)
C# ์ปดํ์ผ๋ฌ๋ ์ฝ๋๋ฅผ ํ์ธต ๋ ๊ฐ๊ฒฐํ๊ฒ ๋ง๋ค ์ ์๋๋ก ํ์
์ถ๋ก (ํ์ ์ ์ถ) (Type-Inference)
๋ฅผ ์ง์ํ๋ค.
ํ์
์ถ๋ก ์ ์ด์ฉํ๋ฉด ๋๋ค์์์ ๋งค๊ฐ ๋ณ์์ ํ์
์ ์ ๊ฑฐํ ์ ์๋ค.
1
2
3
4
delegate int MyDelegate(int x, int y);
// C# ์ปดํ์ผ๋ฌ๊ฐ `delegate`์ ์ ์ธ ์ฝ๋๋ก๋ถํฐ ๋ฌด๋ช
ํจ์์ ๋งค๊ฐ ๋ณ์ ํ์
์ ์ถ๋ก ํด๋ธ๋ค.
MyDelegate myDelegate = (x, y) => x + y;
๐ซง Lambda-Expression Why?
๋๋ค์์ผ๋ก ๋ง๋๋ ๋ฌด๋ช ํจ์๋, ๋๋ฆฌ์๋ฅผ ์ด์ฉํ ์ต๋ช ๋ฉ์๋๋ณด๋ค ๊ฐ๊ฒฐํ๋ค.
๋ ๋ฒ๊ฑฐ๋ก์ด ๋ฐฉ๋ฒ๊ณผ ๋ ๊ฐ๊ฒฐํ ๋ฐฉ๋ฒ์ด ๋์์ ์กด์ฌํ๋ ์ด์ ?
๋๋ฆฌ์๋ฅผ ์ด์ฉํ ์ต๋ช ๋ฉ์๋๋C# 2.0
์์ ๋์ , ๋๋ค์์C# 3.0
์์ ๋์ .
ํ์ ํธํ์ฑ์ ์ ์งํ๊ธฐ ์ํด ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ ๋ชจ๋ ์ง์.
1
2
3
4
5
6
7
delegate int MyDelegate(int x, int y);
// ์ต๋ช
-๋ฉ์๋
MyDelegate myDelegate = delegate (int x, int y) { return x + y; };
// ๋๋ค์
MyDelegate myDelegate = (x, y) => x + y;
๐ซง Statement Lambda | ๋ฌธ ํ์์ ๋๋ค์
์ ํ์์ ๋๋ค์
๋ =>
์ฐ์ฐ์์ ์ค๋ฅธํธ์ ์์ ์ฌ์ฉ.
๋ฌธ ํ์์ ๋๋ค์
์ =>
์ฐ์ฐ์์ ์ค๋ฅธํธ์ ์ค๊ดํธ({}
)๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ๋ ๋ธ๋ก์ ์์ฑ.
์ฌ๋ฌ ์ค์ ์ฝ๋๋ฅผ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, return
ํค์๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐํ๊ฐ์ ์ง์ ํ ์ ์๋ค.
๋ฐํ ํ์์ด ์๋ ๋ฌด๋ช
-ํจ์๋ฅผ ๋ง๋ค ์ ์๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
(int x, int y) => { /* ... */ }
(int x, int y) =>
{
// ...
return x + y;
}
( ) => { /* ... */ }
( ) =>
{
// ...
return 0;
}
๐ซ Expression-Tree | ์-ํธ๋ฆฌ
์์ ํธ๋ฆฌ๋ก ํํํ ์๋ฃ ๊ตฌ์กฐ.
์๋ฅผ ๋ค์ด 1 * 2 + (7 - 8)
๊ฐ์ ์์ ํธ๋ฆฌ๋ก ํํํ๋ฉด ์๋๊ณผ ๊ฐ๋ค.
1
2
3
4
5
+
/ \
* -
/ \ / \
1 2 7 8
์ ํธ๋ฆฌ์์ ์ฐ์ฐ์๋ ๋ถ๋ชจ ๋
ธ๋๊ฐ ๋๋ฉฐ, ํผ์ฐ์ฐ์๋ ์์ ๋
ธ๋๊ฐ ๋๋ค.
์ด๋ ๊ฒ ์ ํธ๋ฆฌ๋ก ํํ๋ ์์ ํธ๋ฆฌ์ ์ ๋
ธ๋๋ผ๋ฆฌ ๊ณ์ฐํด์ ์ฐจ๋ก์ฐจ๋ก ๋ฃจํธ๊น์ง ์ฌ๋ผ๊ฐ๋ฉด ์ ์ฒด ์์ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์๋ค.
๐ซง Expression-Tree Why?
์์ ํ C# ์ปดํ์ผ๋ฌ๋ ์๋์ง๋ง,
ํ๋ก๊ทธ๋๋จธ๊ฐ ์ฝ๋ ์์์ ์ง์ ์ ํธ๋ฆฌ๋ฅผ ์กฐ๋ฆฝํ๊ณ ์ปดํ์ผํด์ ์ฌ์ฉํ ์ ์๋ ๊ธฐ๋ฅ์ ์ ๊ณต.
๋ค์ ๋งํด, ํ๋ก๊ทธ๋จ ์คํ ์ค์ ๋์ ์ผ๋ก ๋ฌด๋ช
ํจ์๋ฅผ ๋ง๋ค์ด ์ฌ์ฉํ ์ ์๊ฒ ํด์ค๋ค๋ ์ด์ผ๊ธฐ.
์ ํธ๋ฆฌ ์๋ฃ ๊ตฌ์กฐ๋ ์ปดํ์ผ๋ฌ๋ ์ธํฐํ๋ฆฌํฐ๋ฅผ ์ ์ํ๋ ๋ฐ๋ ์์ฉ.
์ปดํ์ผ๋ฌ๋ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ ๋ฌธ๋ฒ์ ๋ฐ๋ผ ์์ฑ๋ ์์ค ์ฝ๋๋ฅผ ๋ถ์ํด์ ์ ํธ๋ฆฌ๋ก ๋ง๋ ํ, ์ด๋ฅผ ๋ฐํ์ผ๋ก ์คํ ํ์ผ์ ๋ง๋ ๋ค.
๐ซ Expression
๐ซง Expression Class
Expression ํด๋์ค์ ์์ด๋ค(ํ์ ํด๋์ค๋ค).
์ ํธ๋ฆฌ๋ฅผ ๋ค๋ฃจ๋๋ฐ ํ์ํ ํด๋์ค.
System.Linq.Expressions
๋ค์์คํ์ด์ค์ ์ ์๋์ด ์๋ค.
Expression ํด๋์ค๋ ์ ํธ๋ฆฌ๋ฅผ ๊ตฌ์ฑํ๋ ๋
ธ๋๋ฅผ ํํ
๊ทธ๋์ Expression์ ์์๋ฐ๋ ํ์ ํด๋์ค๋ค ์ญ์ ์ ํธ๋ฆฌ์ ๊ฐ ๋
ธ๋๋ฅผ ํํ
Expression ํด๋์ค๋ ํ์ ํด๋์ค๋ค์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ์ญํ ๋ ๋ด๋น
ํ์ ํด๋์ค์ ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋๋ฅผ ์ ๊ณต.
Expression ํด๋์ค ์์ฒด๋ ์ถ์ ํด๋์ค์ด๋ฏ๋ก ์ง์ ์ธ์คํด์ค๋ฅผ ์์ฑํ ์๋ ์๋ค.
๐ซง Expression ๊ตฌํ
Expressin ํด๋์ค์ ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋๋ฅผ ํตํ ๊ฐ์ฒด ์์ฑ.
ํ๋ก๊ทธ๋๋จธ๋ ๊ฐ ๋
ธ๋๊ฐ ์ด๋ค ํ์
์ธ์ง ์ ๊ฒฝ ์ฐ์ง ์๊ณ ๊ฑฐ์นจ์์ด Expression ํ์์ ์ฐธ์กฐ๋ฅผ ์ ์ธํด์ ์ฌ์ฉํ ์ ์๋ค.
ํ์ํ ๊ฒฝ์ฐ์๋ ๊ฐ ์ธ๋ถ ํ์์ผ๋ก ํ๋ณํ์ ํ๋ฉด ๋๋๊น.
์ด๊ฒ์ด ํฉํ ๋ฆฌ ๋ฉ์๋ ํจํด์ ๋งค๋ ฅ.
1
2
3
4
5
Expression const1 = Expression.Constant(1);// ์์ ํํ์ ๊ฐ์ฒด ์์ฑ
Expression param1 = Expression.Parameter(typeof(int), "x"); // ๋งค๊ฐ๋ณ์ ํํ์ ๊ฐ์ฒด ์์ฑ
Expression exp = Expression.Add(const1, param1); // ๋ง์
ํํ์ ๊ฐ์ฒด ์์ฑ
// '1 + x' ๋ฅผ ๋ํ๋ด๋ ์ ํธ๋ฆฌ
๐ซง Expression ์ปดํ์ผ/์คํ
์ ํธ๋ฆฌ๋ ๊ฒฐ๊ตญ โ์โ์ ํธ๋ฆฌ๋ก ํํํ ๊ฒ์ ๋ถ๊ณผ.
๋ค์ ๋งํด, ์คํ ๊ฐ๋ฅํ ์ํ๊ฐ ์๋๋ผ ๊ทธ์ โ๋ฐ์ดํฐโ ์ํ์ ๋จธ๋ฌผ๋ฌ ์๋ค๋ ๋ง.
์์ ์ ํธ๋ฆฌ ์๋ฃ ๊ตฌ์กฐ ์์ ์ ์๋์ด ์๋ ์์ ์คํํ ์ ์์ผ๋ ค๋ฉด ๋๋ค์์ผ๋ก ์ปดํ์ผ๋์ด์ผ ํ๋ค.
๋๋ค์์ผ๋ก์ ์ปดํ์ผ์ Expression<TDelegate>
ํด๋์ค๋ฅผ ์ด์ฉํ๋ค.
(Expression
<- LambdaExpression
<- Expression<TDelegate>
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Expression const1 = Expression.Constant(1);
Expression param1 = Expression.Parameter(typeof(int), "x");
Expression exp = Expression.Add(const1, param1);
// ๋๋ค์ LambdaExpression (์ ํํ๋ ํ์ ํด๋์ค์ธ Expression<TDelegate>) ์์ฑ
Expression<Func<int, int>> lambda1 =
Expression.Lambda<Func<int, int>>( // ๋ฐํ๊ฐ์ด int์ด๊ณ ๋งค๊ฐ๋ณ์๊ฐ int์ธ ๋๋ค์์ ๋ง๋ญ๋๋ค.
exp,
new ParameterExpression[] { (ParameterExpression)param1 });
// ์คํ๊ฐ๋ฅํ ์ฝ๋๋ก ์ปดํ์ผ
Func<int, int> compiledExp = lambda1.Compile();
// ์ปดํ์ผ๋ ๋๋ค์์ ์คํ
Console.WriteLine(compiledExp(3)); // Output : 4
๐ซง Expression ๋๋ค์ ํ์ฉ
๋๋ค์์ ์ด์ฉํ๋ฉด ๋ ๊ฐ๋จํ๊ฒ ์ ํธ๋ฆฌ๋ฅผ ๋ง๋ค ์ ์๋ค.
๋ค๋ง ์ด ๊ฒฝ์ฐ์๋ โ๋์ ์ผ๋กโ ์ ํธ๋ฆฌ๋ฅผ ๋ง๋ค๊ธฐ๋ ์ด๋ ค์์ง๋ค.
Expression ํ์์ โ๋ถ๋ณ (Immutable)โ์ด๊ธฐ ๋๋ฌธ์, ํ ๋ฒ ์ธ์คํด์ค๋ฅผ ๋ง๋ค๋ฉด ์์ ํ ์ ์๋ค.
1
2
3
4
Expression<Func<int, int>> lambda2 = (x) => 1 + x;
Func<int, int> compiledExp = lambda2.Compile();
Console.WriteLine(compiledExp(3)); // Output : 4
๐ซง Expression So?
์ ํธ๋ฆฌ๋ ์ฝ๋๋ฅผ โ๋ฐ์ดํฐโ๋ก์จ ๋ณด๊ดํ ์ ์๋ค.
ํ์ผ์ ์ ์ฅํ ์๋ ์๊ณ ๋คํธ์ํฌ๋ฅผ ํตํด ๋ค๋ฅธ ํ๋ก์ธ์ค์ ์ ๋ฌํ ์๋ ์๋ค.
์ฌ์ง์ด ์ฝ๋๋ฅผ ๋ด๊ณ ์๋ ์ ํธ๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ดํฐ ๋ฒ ์ด์ค ์๋ฒ์ ๋ณด๋ด์ ์คํ์ํฌ ์๋ ์๋ค.
๋ฐ์ดํฐ ๋ฒ ์ด์ค ์ฒ๋ฆฌ๋ฅผ ์ํ ์ ํธ๋ฆฌ๋ LINQ์์ ์ฌ์ฉ๋๋ค
LINQ๋ฅผ ์ดํดํ๋ ค๋ฉด ๋๋ค์๊ณผ ์ ํธ๋ฆฌ๋ฅผ ์ดํดํ๊ณ ์์ด์ผํ๋ค.
๐ซง Expression-Bodied Member | ์ ๋ณธ๋ฌธ ๋ฉค๋ฒ
โ๋ฉ์๋, ์์ฑ(์ธ๋ฑ์), ์์ฑ์, ์ข
๋ฃ์โ์ ๊ณตํต๋ ํน์ง?
๋ชจ๋ ํด๋์ค์ ๋ฉค๋ฒ๋ก์ ๋ณธ๋ฌธ์ด ์ค๊ดํธ๋ก ๋ง๋ค์ด์ ธ ์๋ค.
์ด๋ฌํ ๋ฉค๋ฒ์ ๋ณธ๋ฌธ์ ์(Expression)๋ง์ผ๋ก ๊ตฌํํ๋ ๊ฒ์ด ๊ฐ๋ฅํ๋ค.
๋ฉค๋ฒ => ์
ํํ๋ก ๊ตฌํํ๋ค.
์ด๋ ๊ฒ ์์ผ๋ก ๊ตฌํ๋ ๋ฉค๋ฒ๋ฅผ ์ ๋ณธ๋ฌธ ๋ฉค๋ฒ(Expression-Bodied Member)
๋ผ๊ณ ๋ถ๋ฅธ๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class MyClass
{
private List<int> list = new List<int>();
// ๋ฉ์๋
public void Add(int value) => list.Add(value);
// ์ฝ๊ธฐ ์ ์ฉ ์์ฑ
public int Capacity => list.Capacity;
// ์ฝ๊ธฐ / ์ฐ๊ธฐ ๊ฐ๋ฅํ ์์ฑ, ์ธ๋ฑ์ [1]
public int this[int index]
{
get => list[index];
set => list[index] = value;
}
// ์ธ๋ฑ์ [2]
public int this[int index] => list[index];
// ์์ฑ์, ์ข
๋ฃ์
public MyClass(int value) => this.value = value;
~MyClass() => Console.WriteLine("์๋ฉธ์ ํธ์ถ");
}
๐ซ ๋ฉ๋ชจ/์ฐธ๊ณ
ฮป-Expression
ฮป
๋ ๊ทธ๋ฆฌ์ค ๋ฌธ์์์L
์ ํด๋นํ๋ ๋ฌธ์- ์๋ก ์กฐ ์ฒ์น๋ ์ด ๋ฌธ์๋ฅผ ํจ์ ํ๊ธฐ๋ฅผ ์ํ ๊ธฐํธ๋ก
^
๋ฅผ ์ฌ์ฉํ๋๋ฐ, ์ด๋ ํ๋ฆฐํฐ์์ ์ด๋ ค์์ด ์์ด ฮป๋ก ๋ฐ๊ฟจ๋ค๊ณ ํจ
- ์๋ก ์กฐ ์ฒ์น๋ ์ด ๋ฌธ์๋ฅผ ํจ์ ํ๊ธฐ๋ฅผ ์ํ ๊ธฐํธ๋ก
=>
๋ฅผ ํ์ดํ ์ฐ์ฐ์๋ผ๊ณ ๋ ๋ถ๋ฅธ๋ค.- ์ด ๊ฒฝ์ฐ,
=>
๋ฅผ ์ด์ฉํ ์์ ํ์ดํ ํจ์๋ผ๊ณ ๋ถ๋ฅธ๋ค.
- ์ด ๊ฒฝ์ฐ,
- โ์ด๊ฒ์ด C#์ด๋ค.โ, โMSDNโ
- TODO: LINQ
- TODO: ํฉํ ๋ฆฌ ํจํด (ํฉํ ๋ฆฌ ๋ฉ์๋)
- TODO: ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๋ก ๊ณผ ์ฐ๊ด์ง์ด (์ํธ๋ฆฌ)
๐ซง Lambda-Expression ๋ฐฐ๊ฒฝ
์๋ก ์กฐ ์ฒ์น(Alonzo Church)
1936๋
์ ๊ณ ์ํ ๋๋ค ๊ณ์ฐ๋ฒ(Lambda Calculus : ๋๋ค ๋์)์์ ์ ๋.
- ๋๋ค ๊ณ์ฐ๋ฒ :
- ์ํ ๊ธฐ์ด๋ก ์ ์ฐ๊ตฌํ๋ ์ค, ๋ถ๋ช ํ๊ณ ๊ฐ๊ฒฐํ ๋ฐฉ๋ฒ์ผ๋ก ํจ์๋ฅผ ๋ฌ์ฌํ๊ธฐ ์ํด ๊ณ ์
- ํฌ๊ฒ ํจ์์ ์ ์์ ๋ณ์, ๊ทธ๋ฆฌ๊ณ ํจ์์ ์ ์ฉ์ผ๋ก ๊ตฌ์ฑ
- ์ด ๊ณ์ฐ๋ฒ์์๋ ๋ชจ๋ ๊ฒ์ด ํจ์๋ก ์ด๋ฃจ์ด์ ธ ์์, ์ฌ์ง์ด โ0, 1, 2 โฆโ ๊ฐ์ ์ซ์๋ ํจ์๋ก ํํ
- ๋ฐ๋ผ์ ๋๋ค ๊ณ์ฐ๋ฒ์์๋ ์ด๋ค ๊ฐ์ ๋ณ์์ ๋์ ํ๊ณ ์ถ์ผ๋ฉด ํจ์๋ฅผ ๋ณ์์ ๋์ ํ๋ฉฐ, ์ด๊ฒ์ ํจ์์ ์ ์ฉ์ด๋ผ๊ณ ๋ถ๋ฆ
์ ์์๋ ์กด ๋งค์นด์(John McCarthy)
.
์ด๊ฒ์ ๋จ์ํ ์ํ ์ด๋ก ์ ๊ทธ์น์ง ์๊ณ , ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ ๋์
ํ ์ ์๊ฒ ๋ค๋ ์์ด๋์ด๋ฅผ ์ ์.
50๋
๋ ๋ง์ LISP
๋ผ๋ ์ธ์ด๋ฅผ ๊ฐ๋ฐ.
์ดํ ๋๋ค ๊ณ์ฐ๋ฒ์ ๊ฐ๋
์ ์ดํ ๋ค๋ฅธ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์๋ ๋์
๋์์ผ๋ฉฐ,
C#, C++, Java, Python ๊ฐ์ ์ฃผ๋ฅ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๋ ๋๋ถ๋ถ ๋๋ค์์ ์ง์.