[制作中]Monadとは?


本文はYouTube naver d 2チャンネルのMonadとは?ビデオに基づいて作成された.
Functor
では、なぜFunctorを使用するのか(値を抽出できず、値をmap()メソッドに変更するしかない).

理由。


Functorでは、通常モデリングできない状況をモデリングできます.
  • 値のないエンクロージャ
  • 予測値は将来準備するエンクロージャ
  • 理由。


    Functorで簡単に関数を合成できます.

    無価ケース

    class FOptional<T> implements Functor<T, FOptinoal<?>> {
    	private final T valueOrNull;
        private FOptinal(T valueOrNull) {
        	this.valueOrNull = valueOrNull;
        }
        
        public <R> FOptinal<R> map(Function<T, R> f) {
        	if (valueOrNull == null) // 값이 비어있으면 empty() 호출하고, f 함수는 호출하지 않음
            	return empty();
    		else
            	return of(f.apply(valueOrNull));
        }
        
        public static <T> FOptional<T> of(T a) {
        	return new FOptional<T>(a);
        }
        
        public static <T> FOptional<T> empty() {
        	return new FOptinal<T>(null); // 값이 비어있는 경우 null을 값으로 가지는 Functor를 반환
        }
    実際の使用
    FOptional<String> optionStr = FOptional(null);
    FOptional<Integer> optionInt = optionStr.map(Integer::parseInt);
    nullは、通常の文字列のようにmap関数を適用してもよいし、parseInt関数を伝達してもよい.
    これは完全に同じ論理であり、その値は以下に示す.
    FOptional<String> optionStr = FOptional("1");
    FOptional<Integer> optionInt = optionStr.map(Integer::parseInt);
    使用者はnullcheckを必要としない.nullの場合、論理は直接実行されない.
    これがタイプ安定性を維持しながらnullを符号化する方法である.

    価格の将来のケース

    Promise<Customer> customer = // ...
    Promise<byte[]> bytes = customer.map(Customer::getAddress)	// return Promise<Address>	
    			.map(Address::street)							// return Promise<String>
                .map((String s) -> s.substring(0, 3))			// return Promise<String>
                .map(String::toLowerCase)						// return Promise<String>
                .map(String::getBytes);							// return Promise<byte[]>
    Promise<Customer>まだ値がありませんCustomerです.ただし、FOptionalと同じmapメソッドを用いることができる.文法的にも意味的にも全く同じです.
    これらは非同期演算であり,同期演算と書くことができる.
    非同期演算を合成できます.

    では、リストは何ですか。


    Listもまた、値ではなく、ListであるFunctorである.
    class FList<T> implements Functor<T, FList<?>> {
    	private final ImmutableList<T> list; // 단순히 Functor가 담고 있는 값이 List임
        FList(Iterable<T> value) {
        	this.list = ImmutableList.copyOf(value);
        }
        
        @Override
        public <R> FList<?> map(Function<T, R> f) {
        	ArrayList<R> result = new ArrayList<R>(list.size());
            for (T t : list) {
            	result.add(f.apply(t)); // List의 모든 원소에 함수 f를 적용
            }
            return new FLIst<>(result);
        }
    }
    parseIntメソッドをListの各要素に適用
    List<String> num = Arrays.asList("1", "2", "3", "4", "5");
    List<String> collect1 = num.stream().map(Integer::parseInt).collect(Collectors.toList());
    Scalaの大部分の集合はmap関数を有する.

    Monadは何ですか?


    FunctorあのMonadが何なのかよく知っています!
    MonadはFunctorにflatMap()を追加しました.
    MonadはFunctorの問題を補うために現れた.Functorの問題を理解してください.

    Functorの問題

    FOptional<Integer> tryParse(String s) {
    	try {
        	final int i = Integer.parseInt(s);
            return FOptional.of(i); // 여기서 이미 Functor를 반환
        } catch (NumberFormatException e) {
        	return FOptional.empty();
        }   
    }

    前の例を以下に示します.mapIntegerを超え、戻り値はFOptinal<Integer>である.
    ここは問題ありません.
    mapFOptinal<Integer>を超えているため、戻り値はFOptional<FOptional<Integer>>である.
    すなわち,FunctorがFunctorに囲まれると,関数の合成やフィルタリングが阻害される.

    サンプルコード

    FOptional<Integer> num1 = // ...
    FOptional<FOptional<Integer>> num2 = // ...
    
    FOptional<Date> date1 = num1.map(t -> new Date(t));
    FOptional<Date> date2 = num2.map(t -> new Date(t)); // 컴파일 에러
    Functorは2回も包まれていて、正常に動作しません.
    Butの前に見たtryParseメソッドのように、Functorの値を返す関数は非常に一般的です.
    このため,flatMapが導入された.

    flatMap()

    interface Monad<T, M extends Monad<?,?>> extends Functor<T,M> {
    	M flatMap(Function<T,M> f); // 변형함수 f의 타입인자인 M을 반환
    }
    flatMapも関数をパラメータとするやつで、その関数はTを受け入れてMを返します.
    では、このflatMapMの構造です.

    mapと比較

    mapと比較すると、大きな違いが感じられます.
    interface Funtor<T> {
    	<R> Functor<R> map(Funciton <T,R> f);
    }
    mapFunctor<R>を返し、flatMapMのみを返します.
    これしかありません.

    FlatMapの適用

    FOptional<String> num = FOptional.of("42"):
    
    // tryParse의 반환값: FOptinal<Integer>
    FOptional<Integer> answer = num.flatMap(this::tryParse);
    
    FOptional<Date> date = answer.map(t -> new Date(t)); // 합성 가능
    これこそflatMapこれこそ本当の意味です.
    num.flatMap(this::tryParse)
    	.map(t -> new Date(t)); 
        .flatMap
        .
        .
    flatMapが完了すると、結果はmapであってもよいし、flatMapであってもよい.
    (ゆっくりでいい)
    このような合成をMonadの優位性と言える.

    n/a.結論


    Monadの定義

  • Monadは値容器
  • Functor実装
  • flatMap()メソッド
  • Monad Lawsの実装
  • Monadの意味

  • 値がない場合、将来値が発生する可能性がある場合などの一般的な状況をモデリングできます.
  • 非同期ロジックは同期ロジックの実装形式と同じであるが、関数の合成と完全にブロックされていないplpelineを実装することができる.