Kleisli Catogories

2022. 10. 17. 00:00Functional 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 이다. 

 

 

 

관련영상

https://youtu.be/Ty-WErI7Q4Q

 

반응형

'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