Monad

2022. 11. 21. 00:00Functional Programming/Category Theory

반응형

 

모나드는 Flatten이 되는 Functor 이다. 

 

지금까지 우리가 여러가지 개념을 배웠고 그러면서 이전시간 까지 Functor 에 대해 배웠다

그리고 Functor 중 몇몇을 예로 들어 설명하였다. 

 

Monad 는 Flatten 이 되는 Functor 이다. 

 

이것이 monad 의 개념이다.

 

우리가 Flatten 이 무엇이지 Functor 가 무엇인지 모른다면 이 개념처럼 모호한 개념이 없다. 

 

Flatten

 List<List<string>> ==> Flatten ==> List<string> 

 

Functor

  • 사용자가 맵핑 할 수있는 데이터 타입 
  • 내부의 값에 함수를 적용하는 인터페이스가 있는 컨테이너
  • “mappable” 한 무언가

 

물론 그 안에는 더 많은 개념이 있다. 

하지만 기본적인 정의는 위와 같이 표현할 수 있다. 

Flatten 은 말로 표현하는 것보다 sampe 이 더 이해하기 쉬울것이다. 

결과적으로 unwrapping 하는 것이므로 그렇게 이해하면 된다. 

 

https://yogingang.tistory.com/375

 

Category : The Essence of Composition (Category: Composition 의 본질)

참고 : https://bartoszmilewski.com/2014/11/04/category-the-essence-of-composition/ Category 는 개체와 개체 사이를 이동하는 화살표로 구성된다. Category 의 본질은 Composition 이다. 객체 A 에서 B 로의 화살표와 객체 B

yogingang.tistory.com

 

https://yogingang.tistory.com/384

 

Functor

참고 : https://bartoszmilewski.com/2015/01/20/functors/ functor는 두 범주 간의 매핑이다. 펑터는 객체뿐만 아니라 객체 간의 기능(모피즘이라고 함)도 매핑한다. 예를 들어, 펑터 F는 카테고리 C와 D 사이의 매

yogingang.tistory.com

 

Monad 는 다음과 같은 구현이 필요하다

bind   :: m a -> (a -> m b) -> m b
return :: a -> m a

Bind 는 FlatMap 이라고도 하고 C# 에서는 SelectMany 라고도 한다. 

Bind 는 M<A> 값이 들어왔을때 이것을 fmap 하는 과정중에

M<M<A>> 형태로 처리하게 되는 문제를 해결하기 위한 것이다.

 

Flat 이란 저 M<M<A>> 를 M<A> 형태로 unwrap 해준다. (flat)

 

List<List<string>> 형태를 SelectMany 를 통해 List<string> 형태로 바꾸는것과 동일 한다. 

 

어쨌든 Monad 는 저 bind 와 return 이 필요하다. 

 

Return 은 a 라는 값을 받아 M<A> 형태로 Monad 즉 Container 안에 집어 넣어 return 하는 함수 이다. 

 

 

C# Nullable Monad ( Maybe ?? )

 

이제 C# 에서 사용하고 있는 Monad 와 가장 비슷한 내용을 구현해 보겠다. 

실제 C# 에서 언어적 한계로 인해 Haskell 같이 추상화된 Monad를 사용하기는 어렵다. 

아래 구현을 보자

 

int?  : int 이거나 null 을 갖을 수 있는 c# 형 Maybe Monad (완전히 같지는 않다.)

이것은 실제 Nullable<int> 와 일치 한다. 

 

int? f() { return 5; }
int? g() { return 7; }
int? h() { return 9; }
int? z = f().Bind(fval => g().Bind(gval => h().Bind(hval =>
                                   new int?(fval + gval + hval))));

 

아래는 Bind 에 대한 Extension Method 이다. 

public static B? Bind<A, B>(this A? a, Func<A, B?> f)
where B : struct
where A : struct
{
    return a.HasValue ? f(a.Value) : null;
}

Nullable<A> 가 값을 가지면 (HasValue) Function f 를 실행하고  그렇지 않다면 null 을 return 한다. 

실제 위의 코드를 실행하면 z = 21 이라는 값이 나온다. 

만약 f , g, h 중 하나라도 null 을 갖는다면 Bind 함수에 의해  z = null 을 return 받게 된다. 

 

Bind 함수를 보면 

A? a  를  m a 

Func<A, B?> 를 (a -> m b) 

B?  를  m b 

라고 볼 수 있다. 이를 다시 표현해 보면

A? a ,  Func<A,B?> f   return B?

m a  ->  (a -> m b) --> m b

m a -> (a -> m b) -> m b

위와 같이 해석 할 수 있게 된다. 

즉 Nullable 의 Bind 는  Monad 의 bind 규칙과 일치한다. 

 

사실 C# 에서도 ReaderMonad 니 WriterMonad 니 하는 것들을 구현 가능하다

F# 과 비슷하게 Option, Lift 등등을 구현할 수도 있다. 

하지만 이러한 것들은 언어적 한계점으로 인해 많이 부족한 점을 보인다. 

혹자는 https://github.com/louthy/language-ext 를 이용하여

이러한 부족한 점을 채우는 방법이 있다고 하지만

실상 그와 같은 것을 쓰게 된다면 ..

결국에는 F# 으로 Library 를 만들어 활용(?) 하는 것이 더욱 나을 수 있다.

 

일단 Functional Programming 에 대한 내용은 여기 까지다.

좀 많은 시간을 들여서 Category Theory 부터 달려왔었다. 

결과적으로 모든것을 이해했던것은 아니지만 Functional Programming 에서 사용하는

많은 Pattern 들에 대해 알아보게된 계기가 되었다고 생각한다. 

 

향후에 OOP 안에서 Function 관련된 부분에 이러한 Compose , Bind, Flat 같은 개념들을 사용하고

c# 에서 Monad 를 활용하는 가장 좋은 방법을 알게 된다면

다시 한번 이곳에서 이부분에 대한 이야기를 하게 될것 같다. 

 

Free Monad 로 DSL (Flow) 을 만들고

CoPilot 같은 AI 도구로 단위 Function 을 생성하고

단위 Funtion 과 단위 Function 을 Compose 하여 원하는 수준의 개발을 할 수 있게되면 그때 다시 이야기 해보겠다.

 

관련영상

https://youtu.be/CGCRD770pn4

 

반응형

'Functional Programming > Category Theory' 카테고리의 다른 글

Contravariant Functor, Profunctor  (0) 2022.11.14
ApplicativeFunctor, BiFunctor  (0) 2022.11.07
Functor  (0) 2022.10.31
Product and CoProduct  (0) 2022.10.24
Kleisli Catogories  (0) 2022.10.17