2022. 10. 17. 00:00ㆍFunctional Programming/Category Theory
참조 : https://bartoszmilewski.com/2014/12/23/kleisli-categories/
실행 내역을 기록하거나 추적하는 함수를 예로 들어 보자.
즉 로깅을 구현하다고 해보자.
private string _logger;
public bool Not(bool value)
{
_logger += $"Not {value}";
return !value;
}
member 변수 (전역) _logger 의 변경으로 인하여 이것은 부작용이 있고 그렇기 때문에 순수함수가 아니다.
Concurrency 의 복잡성 때문에 전역 변경 상태를 피해야 한다.
이것을 순수하게 만들어 보자
public (bool Result, string Logger) Not(bool value, string logger)
{
return (!value, logger + $"Not {value}");
}
입력으로 이전 logger 를 전달해야 하기 때문에 불편할 수 있다.
관심의 분리라는 관점에서 접근해보면 (SRP 의 관점으로 접근해도 된다.)
logger 에 이전 log 를 쌓는 기능을 Not 이 할 필요는 없다.
즉 다음과 같이 수정해도 된다.
public (bool Result, string Logger) Not(bool value)
{
return (!value, $"Not {value}");
}
The Writer Category
이제 bool 과 string 형의 튜플을 리턴하는 writer 라는 category 를 만들어 보자
public (bool Result, string Logger) NotNormal(bool value)
{
var p1 = Not(value);
var p2 = Normal(p1.Result);
return (p2.Result, p1.Logger + p2.Logger);
}
var data = NotNormal(true);
WriteLine($"result : {data.Item1}, log ; {data.Item2} ");
// result : False, log ; !True False
일단 Not 과 Normal 을 이용해서 NotNormal 이라는 새로운 function 을 만들었다.
특별한 작업을 하는건 아니고 true 를 넣으면 false 를 리턴하게 된다.
Normal 은 여기서 identity 이다.
물론 log 라는 string 을 표시하는것이 우리가 하려는 일이다.
WriteLine 을 보면 log 를 제대로 찍는것을 볼수 있다.
자 이것은 크게 의미있는 예제는 아니었다.
그럼 실제로 function 의 가장 작은 단을 만들어서 Composition 을 해보겠다.
public (bool Result, string Logger) IsEven(int n) => (n % 2 == 0, "isEven ");
public (bool Result, string Logger) IsOdd(int n)
{
var p1 = IsEven(n);
var p2 = Not(p1.Result);
return (p2.Result, p1.Logger + p2.Logger);
}
var data = IsOdd(3);
WriteLine($"result : {data.Item1}, log ; {data.Item2} ");
// result : True, log ; isEven !False
// 3은 isEven 을 not 하여 만들어낸다.
// 로그의 의미는 IsEven 을 호출 한 후 그결과를 Not 을 통해 다시 호출 했다는 것이다.
// 이렇게 합성하면 IsOdd 가 된다.
// IsOdd 를 (n % 2 == 1, "isOdd "); 로 구현 하지 않고
// 기존 함수들을 Composition 한것이 핵심이다.
이제 위에 내용들을 보면서 뭔가 공통점이 보이지 않는가?
맞다 이제 이부분을 일반(추상)화 해보자.
public Func<A, (C, string)> Compose<A,B,C>(Func<A, (B, string)> f, Func<B, (C, string)> g)
{
return (A x)=>
{
var p1 = f(x);
var p2 = g(p1.Item1);
return (p2.Item1, p1.Item2 + p2.Item2);
};
}
var isOdd = Compose<int, bool, bool>(IsEven, Not);
data = isOdd(3);
//result : True, log ; isEven !False
Compose 라는 Generic 함수를 생성하여 int --> bool --> bool 형태로 처리되도록 하였다.
내 부적으로는 tuple 이기 때문에 a->(b,string) -> b ->(c,string) 형태가 되겠다.
자 이것은 monad 를 기반으로 하는 Kleisli Category 이다.
관련영상
'Functional Programming > Category Theory' 카테고리의 다른 글
Functor (0) | 2022.10.31 |
---|---|
Product and CoProduct (0) | 2022.10.24 |
Monoid as Category (0) | 2022.10.10 |
Types and Functions (0) | 2022.10.03 |
Category : The Essence of Composition (Category: Composition 의 본질) (0) | 2022.09.26 |