2022. 9. 14. 00:00ㆍCSharp/Functional Programming
Higher Order Function (HOF) 는 하나 이상의 함수를 인수로 취하거나, 함수를 반환하거나, 둘 모두를 수행하는 함수다. 우리는 정수나 문자열과 같은 단순한 객체 또는 컬렉션 및 사용자 정의 유형과 같은 더 복잡한 객체를 함수 매개변수로 전달하는 데 익숙하다. 그러나 C#은 HOF도 잘 지원한다. 이것은 delegate 와 람다 식을 사용하여 수행된다.
일단 delegate 와 lambda 에 대해 간단히 알아보자
x 와 y 의 값을 입력 받아 둘을 더해 그 결과값을 return 하는 method 를 만든다고 생각해 보자
delegate 를 통해 이 method 를 위임받아 처리 하려면 다음과 같이 한다.
private delegate int Add(int x, int y); //delegate 선언
public void Test()
{
Add add = AddMethod; // Add delegate 에 AddMethod 할당
var result = add(1, 2); // delegate 를 통해 실행
Console.WriteLine(result);
}
public int AddMethod(int x, int y)
{
return x + y;
}
똑같은 내용을 lambda 식을 사용하여 처리 해보자 . lambda 식을 사용할때는 Func<> 을 이용한다.
public void Test()
{
Func<int,int,int> add = ( x, y) => x + y; //lambda 식을 Func 에 할당
//var add = (int x, int y) => x + y; // var 을 통해 할당 받을때는 타입을 지정한다.
var result = add(1, 2); // 실행
Console.WriteLine(result);
}
delegate 에 대한 자세한 내용은 다음 강좌를 참고하자
https://yogingang.tistory.com/24
Delegate (대리자)
특정 매개 변수 목록 및 반환 형식이 있는 메서드에 대한 참조를 나타내는 형식. 접근제어자 + delegate + 반환형 + 대리자명 + (전달인수) public delegate int PerformCalculation(int x, int y); 대리자는 C++..
yogingang.tistory.com
lambda 에 대한 자세한 내용은 다음 강좌를 참고하자
https://yogingang.tistory.com/26
Action, Func, Lambda
Action 매개 변수가 없고 값을 반환하지 않는 메서드를 캡슐화 한 대리자 (delegate) Action 매개 변수가 하나이고 값을 반환하지 않는 메서드를 캡슐화 한 대리자 (delegate) Action 매개 변수가 n 개이고
yogingang.tistory.com
https://yogingang.tistory.com/27
Lambda advanced
C# 10 에서 lambda 개선 사항 Attribute 속성이 있는 람다 허용 속성은 람다 식 및 람다 매개 변수에 추가할 수 있다. 메서드 특성과 매개변수 특성 간의 모호성을 피하기 위해 특성이 있는 람다 표현식
yogingang.tistory.com
이제 기본적인 개념을 알았다고 가정하고 HOF 에 대해 알아 보겠다.
그전에 LINQ 를 사용해 본적이 있다면 HOF 를 사용해 본적이 있다고 말할 수 있겠다.
var numbers = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var even = numbers.Where(x => x % 2 == 0);
// => [2, 4, 6, 8]
Func<int, bool> isOdd = x => x % 2 != 0; // assign lambda expression to Func
var odd = numbers.Where(isOdd);
// => [1, 3, 5, 7, 9]
여기서 HOF 의 좋은 예는 바로 Where 이다. Where 는 다음과 같이 선언되어 있다.
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
Where 는 함수를 매개변수를 받게 되어있다. (predicate)
이를 이용해서 호출하는 쪽에서는 결과에 포함하거나 제외해야 하는 항목을 function 을 통해 전달 할 수 있다.
이번에는 함수를 반환 하는 경우를 예로 들어보자
Func<int, bool> IsDivisible(int n)
{
return x => x % n == 0;
}
public void ReturnFunc()
{
var numbers = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var num3 = numbers.Where(IsDivisible(3));
// => [3, 6, 9]
}
이미 정의된 Function 의 Interface 를 변경 할 수도 있다.
(처음 Functional Progrmming 을 접하게되면 지금까지 많은 편견들을 가지고 있었다는 것에 놀라움을 느끼게 된다.
명령형 programming 에서
static type 형태의 language 를 익히고
compile 과 build 가 필요한 환경에서
OOP 위주의 교육을 받았던 programmer 들이라면 더욱 공감할 것이다.
이제 아래 내용을 확인하면 자신이 아주 좁은 경계에서 프로그래밍을 익혔다는 것을 알게 될것이다.
세상은 빠르게 변해가고 programming 도 변하고 있다.....아니 이미 변하였다.)
다음과 같은 Function 이 있다고 하자 이 Function 은 2개의 입력값을 받아서 x 를 y 로 나눈 몫을 return 한다.
Func<int, int, int> divide = (x, y) => x / y;
divide(6, 2); // => 3
이제 divide 라는 함수 자체를 변경하지 않고 x 와 y 의 순서를 바꾸어 실행되도록 변경해 보자
public static class SwapExtensions
{
public static Func<T2, T1, R> Swap<T1, T2, R>(this Func<T1, T2, R> f)
=> (t2, t1) => f(t1, t2);
}
var divideBy = divide.Swap();
divideBy(2, 6); // => 3
Swap 는 Function 을 인수로 받아서 T2,T1 으로 들어온 값을 T1,T2 로 변경하여 인수로 받은 Function 을 실행 시킨다.
Functional Programming 에 익숙한 사람들은 그냥 일상적인 내용이겠지만
처음 익히는 경우는 놀라운 광경이다....
(Functional Programming 만세 삼창을 한 후 오늘 하루를 마무리 짓자!!)
관련 영상
'CSharp > Functional Programming' 카테고리의 다른 글
순수 함수 (Pure Function) (0) | 2022.09.19 |
---|---|
Expression, Method chaining with Extension methods (0) | 2022.09.16 |
Functors (Map, Filter, Reduce) (0) | 2022.09.15 |
Immutable type or object (0) | 2022.09.13 |
Functional Programming 의 두가지 기본 개념 (0) | 2022.09.12 |