C# · 심층 가이드
C# 함수형 완전 정리
순수 함수와 불변 업데이트에서 시작해 Maybe와 Result 흉내내기, fold, 커링, 지연 이터레이터까지 C#에서 함수형 스타일을 쓰는 열다섯 가지 방법입니다.
C#은 함수형 언어가 아니지만 함수형 스타일을 쓰기에는 재료가 꽤 갖춰져 있습니다. 람다와 LINQ가 오래전에 자리를 잡았고, record가 불변 데이터를, 패턴 매칭과 switch 식이 대수적 자료형 흉내를 어느 정도 감당합니다. 다만 Option이나 Result가 표준으로 들어 있지는 않아서, 이 절의 상당수는 언어가 주는 조각으로 그 개념을 직접 조립하는 연습이 됩니다. 라이브러리를 통째로 들이지 않고도 어디까지 갈 수 있는지, 그리고 어디서부터는 무리인지를 가늠하는 데 목적이 있습니다.
순수 함수와 불변 업데이트가 나머지를 떠받치는 두 기둥입니다. 여기서 Maybe 스타일 처리와 Result 스타일 매핑으로 가면 값이 없을 수 있는 상황과 실패할 수 있는 상황을 예외 대신 타입으로 표현하는 방법이 나오고, 패턴 분기가 그 값을 꺼내는 짝이 됩니다. compose, partial 적용, curried 함수는 한 묶음으로 읽어야 pipeline에서 왜 그 형태가 필요했는지 이어집니다.
lazy iterator에서 yield return을 쓸 때는 실행 시점을 조심해야 합니다. 이터레이터 메서드는 호출만으로는 몸체가 한 줄도 돌지 않고, 첫 열거가 시작될 때 비로소 실행됩니다. 그래서 메서드 맨 앞에 넣은 인자 검증도 그때까지 미뤄져, 잘못된 인자를 넘긴 호출 지점이 아니라 한참 뒤의 foreach에서 예외가 터집니다. 검증은 일반 메서드에서 하고 열거 부분만 따로 떼어 내는 방식이 정석입니다. 재귀 쪽도 마찬가지로, C#은 꼬리 재귀 최적화를 보장하지 않으니 깊은 재귀는 반복문이나 명시적 스택으로 바꿔야 합니다.
01순수 함수
C#에서 순수 함수 개념을 코드로 빠르게 확인하는 함수형 예제입니다.
C# code
// 순수 함수
using System;
using System.Linq;
var values = new[] { 1, 2, 3, 1 };
Console.WriteLine(values.Aggregate(0, (sum, value) => sum + value));함수형 예제는 입력과 출력이 분명할수록 재사용과 테스트가 쉬워진다는 점이 핵심입니다.
원본 데이터를 직접 바꾸기 시작하면 함수형 스타일의 장점이 크게 줄어듭니다.
02불변 업데이트
C#에서 불변 업데이트 개념을 코드로 빠르게 확인하는 함수형 예제입니다.
C# code
// 불변 업데이트
using System;
var state = new { Page = 1, Tags = new[] { "x" } };
var next = new { Page = state.Page + 1, Tags = state.Tags.Append("y").ToArray() };
Console.WriteLine(next.Page);함수형 예제는 입력과 출력이 분명할수록 재사용과 테스트가 쉬워진다는 점이 핵심입니다.
원본 데이터를 직접 바꾸기 시작하면 함수형 스타일의 장점이 크게 줄어듭니다.
03Maybe 스타일 처리
C#에서 Maybe 스타일 처리 개념을 코드로 빠르게 확인하는 함수형 예제입니다.
C# code
// Maybe 스타일 처리
using System;
using System.Linq;
var values = new[] { 1, 2, 3, 3 };
Console.WriteLine(values.Aggregate(0, (sum, value) => sum + value));함수형 예제는 입력과 출력이 분명할수록 재사용과 테스트가 쉬워진다는 점이 핵심입니다.
원본 데이터를 직접 바꾸기 시작하면 함수형 스타일의 장점이 크게 줄어듭니다.
04Result 스타일 매핑
C#에서 Result 스타일 매핑 개념을 코드로 빠르게 확인하는 함수형 예제입니다.
C# code
// Result 스타일 매핑
using System;
var state = new { Page = 1, Tags = new[] { "x" } };
var next = new { Page = state.Page + 1, Tags = state.Tags.Append("y").ToArray() };
Console.WriteLine(next.Page);함수형 예제는 입력과 출력이 분명할수록 재사용과 테스트가 쉬워진다는 점이 핵심입니다.
원본 데이터를 직접 바꾸기 시작하면 함수형 스타일의 장점이 크게 줄어듭니다.
05fold 합계
C#에서 fold 합계 개념을 코드로 빠르게 확인하는 함수형 예제입니다.
C# code
// fold 합계
using System;
using System.Linq;
var values = new[] { 1, 2, 3, 5 };
Console.WriteLine(values.Aggregate(0, (sum, value) => sum + value));함수형 예제는 입력과 출력이 분명할수록 재사용과 테스트가 쉬워진다는 점이 핵심입니다.
원본 데이터를 직접 바꾸기 시작하면 함수형 스타일의 장점이 크게 줄어듭니다.
06compose
C#에서 compose 개념을 코드로 빠르게 확인하는 함수형 예제입니다.
C# code
// compose
using System;
var state = new { Page = 1, Tags = new[] { "x" } };
var next = new { Page = state.Page + 1, Tags = state.Tags.Append("y").ToArray() };
Console.WriteLine(next.Page);함수형 예제는 입력과 출력이 분명할수록 재사용과 테스트가 쉬워진다는 점이 핵심입니다.
원본 데이터를 직접 바꾸기 시작하면 함수형 스타일의 장점이 크게 줄어듭니다.
07partial 적용
C#에서 partial 적용 개념을 코드로 빠르게 확인하는 함수형 예제입니다.
C# code
// partial 적용
using System;
using System.Linq;
var values = new[] { 1, 2, 3, 7 };
Console.WriteLine(values.Aggregate(0, (sum, value) => sum + value));함수형 예제는 입력과 출력이 분명할수록 재사용과 테스트가 쉬워진다는 점이 핵심입니다.
원본 데이터를 직접 바꾸기 시작하면 함수형 스타일의 장점이 크게 줄어듭니다.
08curried 함수
C#에서 curried 함수 개념을 코드로 빠르게 확인하는 함수형 예제입니다.
C# code
// curried 함수
using System;
var state = new { Page = 1, Tags = new[] { "x" } };
var next = new { Page = state.Page + 1, Tags = state.Tags.Append("y").ToArray() };
Console.WriteLine(next.Page);함수형 예제는 입력과 출력이 분명할수록 재사용과 테스트가 쉬워진다는 점이 핵심입니다.
원본 데이터를 직접 바꾸기 시작하면 함수형 스타일의 장점이 크게 줄어듭니다.
09pipeline
C#에서 pipeline 개념을 코드로 빠르게 확인하는 함수형 예제입니다.
C# code
// pipeline
using System;
using System.Linq;
var values = new[] { 1, 2, 3, 9 };
Console.WriteLine(values.Aggregate(0, (sum, value) => sum + value));함수형 예제는 입력과 출력이 분명할수록 재사용과 테스트가 쉬워진다는 점이 핵심입니다.
원본 데이터를 직접 바꾸기 시작하면 함수형 스타일의 장점이 크게 줄어듭니다.
10lazy iterator
C#에서 lazy iterator 개념을 코드로 빠르게 확인하는 함수형 예제입니다.
C# code
// lazy iterator
using System;
var state = new { Page = 1, Tags = new[] { "x" } };
var next = new { Page = state.Page + 1, Tags = state.Tags.Append("y").ToArray() };
Console.WriteLine(next.Page);함수형 예제는 입력과 출력이 분명할수록 재사용과 테스트가 쉬워진다는 점이 핵심입니다.
원본 데이터를 직접 바꾸기 시작하면 함수형 스타일의 장점이 크게 줄어듭니다.
11패턴 분기
C#에서 패턴 분기 개념을 코드로 빠르게 확인하는 함수형 예제입니다.
C# code
// 패턴 분기
using System;
using System.Linq;
var values = new[] { 1, 2, 3, 11 };
Console.WriteLine(values.Aggregate(0, (sum, value) => sum + value));함수형 예제는 입력과 출력이 분명할수록 재사용과 테스트가 쉬워진다는 점이 핵심입니다.
원본 데이터를 직접 바꾸기 시작하면 함수형 스타일의 장점이 크게 줄어듭니다.
12reducer 상태 누적
C#에서 reducer 상태 누적 개념을 코드로 빠르게 확인하는 함수형 예제입니다.
C# code
// reducer 상태 누적
using System;
var state = new { Page = 1, Tags = new[] { "x" } };
var next = new { Page = state.Page + 1, Tags = state.Tags.Append("y").ToArray() };
Console.WriteLine(next.Page);함수형 예제는 입력과 출력이 분명할수록 재사용과 테스트가 쉬워진다는 점이 핵심입니다.
원본 데이터를 직접 바꾸기 시작하면 함수형 스타일의 장점이 크게 줄어듭니다.
13all predicate
C#에서 all predicate 개념을 코드로 빠르게 확인하는 함수형 예제입니다.
C# code
// all predicate
using System;
using System.Linq;
var values = new[] { 1, 2, 3, 13 };
Console.WriteLine(values.Aggregate(0, (sum, value) => sum + value));함수형 예제는 입력과 출력이 분명할수록 재사용과 테스트가 쉬워진다는 점이 핵심입니다.
원본 데이터를 직접 바꾸기 시작하면 함수형 스타일의 장점이 크게 줄어듭니다.
14flatMap
C#에서 flatMap 개념을 코드로 빠르게 확인하는 함수형 예제입니다.
C# code
// flatMap
using System;
var state = new { Page = 1, Tags = new[] { "x" } };
var next = new { Page = state.Page + 1, Tags = state.Tags.Append("y").ToArray() };
Console.WriteLine(next.Page);함수형 예제는 입력과 출력이 분명할수록 재사용과 테스트가 쉬워진다는 점이 핵심입니다.
원본 데이터를 직접 바꾸기 시작하면 함수형 스타일의 장점이 크게 줄어듭니다.
15함수 값을 반환하는 함수
C#에서 함수 값을 반환하는 함수 개념을 코드로 빠르게 확인하는 함수형 예제입니다.
C# code
// 함수 값을 반환하는 함수
using System;
using System.Linq;
var values = new[] { 1, 2, 3, 15 };
Console.WriteLine(values.Aggregate(0, (sum, value) => sum + value));함수형 예제는 입력과 출력이 분명할수록 재사용과 테스트가 쉬워진다는 점이 핵심입니다.
원본 데이터를 직접 바꾸기 시작하면 함수형 스타일의 장점이 크게 줄어듭니다.
정리하며
- 표준
Option과Result가 없으므로 필요한 만큼만 직접 만들어 씁니다 yield return메서드는 첫 열거 전까지 실행되지 않아 인자 검증이 지연됩니다- 꼬리 재귀 최적화가 보장되지 않으니 깊은 재귀는 반복이나 명시적 스택으로 바꿉니다
- 불변 업데이트는 원본을 두고 새 값을 만들되 내부 컬렉션 공유 여부를 확인합니다
더 깊이 들어가고 싶다면 C# 학습 라이브러리에서 다른 주제 가이드를 이어서 보거나, 언어 비교에서 같은 개념이 다른 언어에서 어떻게 표현되는지 확인해 보세요.