본문 바로가기

연재작/프로그래밍 언어

monad 패턴, optional, promise, stream

Monad 패턴이란?

함수형 인터페이스에서 등장하는 디자인 패턴 개념으로,

함수(메서드)에 return값 (Value)을 특정한 타입으로 감싸는 형태의 패턴이다.

 

모나드 패턴은 두 개의 operator를 정의하는데,

  1. Unit : 모나드 타입으로 감싸는 형태의 operator 
  2. Bind : 모나드 타입으로 감싸져 있는 것을 다른 함수에 적용한 후 , 다시 모나드로 반환하는 연산자이다.
  3. Associativity : 연산이 체인될 때 순서와 상관없이 동일한 결과를 보장해야 함.
    수학에서의 그 결합법칙이다. 찾아보니 Monad 라는 패턴은 수학에서의 범주론에서 다루는 내용이라
    그 내용이 수학에서의 것과 동일하다.

 

 

이러한 관점에서 보았을 때

Optional

Optional은 모나드 패턴이다.

Optional<String> unit = Optional.of("Hello"); // Optional.ofNullable("Hello") 도 가능은 함.

Optional<Integer> bind = Optional.of("123")
		.flatMap(s -> Optional.of(Integer.parseInt(s))); // Optioanl[123]

Optional<Integer> result1 = Optional.of("123")
		.flatMap(s -> Optional.of(Integer.parseInt(s)))
        .flatMap(i -> Optional.of(i * 2)); 				// Optional[246]
Optional<Integer> result2 = Optional.of("123")
		.flatMap(s -> Optional.of(Integer.parseInt(s) * 2 )) // Optional[246]

 

stream이 monad가 아닌이유?

Stream<String> stream1 = Stream.of("123")
        .flatMap(s -> Stream.of(s + s));

Stream<String> stream2 = Stream.of("123")
        .flatMap(s -> Stream.of(s))
        .flatMap(s -> Stream.of(s + s));

// 스트림은 한 번 소비되면 재사용할 수 없기 때문에 연산이 달라질 수 있음.
System.out.println(stream1.equals(stream2));  // false
// 값은 123123으로 같게 나왔지만 두 개의 참조 파이프라인을 살펴보니 달랐다.
// java.util.stream.ReferencePipeline$7@7e9e5f8a
// java.util.stream.ReferencePipeline$7@8bcc55f

 

➡️ associativity 가 성립하지 않음. 
항등함수와 s+s함수가 결합했는데 원래의 값과 다르게 나온 셈이 되는 것이다.

 

promise가 monad가 아닌이유?

let result1 = Promise.resolve("abc")
    .then(s => Promise.resolve(parseInt(s)))  // 실패: "abc"는 숫자가 아님
    .then(i => Promise.resolve(i * 2))
    .catch(error => {
        console.log("Result 1 failed with error:", error);
        return "Result 1 failed";  // 오류가 발생하면 대체 값 반환
    });

let result2 = Promise.resolve("abc")
    .then(s => Promise.resolve(parseInt(s) * 2))  // 먼저 두 배로, 여기서 실패
    .catch(error => {
        console.log("Result 2 failed with error:", error);
        return "Result 2 failed";  // 오류가 발생하면 대체 값 반환
    });

Promise.all([result1, result2])
    .then(values => {
        console.log("Result 1:", values[0]);  // "Result 1 failed"
        console.log("Result 2:", values[1]);  // "Result 2 failed"
    });

 

➡️ Promise는 일단 실패가 되는 지점은 서로 동일하다고 볼 수 있으나,

catch 구문에서 실패에 대한 분기처리, 즉 다른 값을 반환 할 수 있는 경우가 존재하기에

associativity를 따른다고 볼 수 없다.

 

 

 

 

 

 

https://en.wikipedia.org/wiki/Monad_(functional_programming)

 

Monad (functional programming) - Wikipedia

From Wikipedia, the free encyclopedia Design pattern in functional programming to build generic types In functional programming, a monad is a structure that combines program fragments (functions) and wraps their return values in a type with additional comp

en.wikipedia.org