모나드는 Java로 구현 될 수 있지만, 모나드를 포함하는 모든 계산은 제네릭과 중괄호가 뒤죽박죽이 될 운명입니다.
Java는 작업을 설명하거나 의미와 본질을 연구하기 위해 사용하는 언어가 아닙니다 . 이를 위해 JavaScript를 사용하거나 추가 비용을 지불하고 Haskell을 배우는 것이 훨씬 좋습니다.
어쨌든 새로운 Java 8 lambda를 사용하여 상태 모나드 를 구현했음을 알려드립니다 . 확실히 애완 동물 프로젝트이지만 사소한 테스트 케이스에서 작동합니다.
내 블로그 에서 찾을 수 있지만 여기에서 몇 가지 세부 정보를 제공하겠습니다.
상태 모나드는 기본적으로 상태에서 쌍 (state, content)으로의 함수입니다 . 일반적으로 상태에 일반 유형 S를 제공하고 콘텐츠에 일반 유형 A를 제공합니다.
Java에는 쌍이 없기 때문에 특정 클래스를 사용하여 모델링해야합니다. Scp (상태-콘텐츠 쌍)라고 부르겠습니다.이 경우에는 일반 유형 Scp<S,A>
과 생성자를 갖습니다 new Scp<S,A>(S state,A content)
. 그런 다음 모나 딕 함수에 유형이 있다고 말할 수 있습니다.
java.util.function.Function<S,Scp<S,A>>
이는 @FunctionalInterface
. 즉, 올바른 유형의 람다 식을 전달하여 이름을 지정하지 않고 유일한 구현 메서드를 호출 할 수 있습니다.
클래스 StateMonad<S,A>
는 주로 함수를 감싸는 래퍼입니다. 생성자는 예를 들어 다음과 같이 호출 될 수 있습니다.
new StateMonad<Integer, String>(n -> new Scp<Integer, String>(n + 1, "value"));
상태 모나드는 함수를 인스턴스 변수로 저장합니다. 그런 다음 액세스하고 상태를 제공하는 공용 메소드를 제공해야합니다. 나는 그것을 s2scp
( "state to state-content pair")라고 부르기로 결정했습니다 .
모나드의 정의를 완료하려면 유닛 (일명 return )과 bind (일명 flatMap ) 메소드를 제공해야합니다. 개인적으로 나는 단위를 정적으로 지정하는 것을 선호하지만 bind는 인스턴스 멤버입니다.
상태 모나드의 경우 단위는 다음과 같아야합니다.
public static <S, A> StateMonad<S, A> unit(A a) {
return new StateMonad<S, A>((S s) -> new Scp<S, A>(s, a));
}
bind (인스턴스 멤버)는 다음과 같습니다.
public <B> StateMonad<S, B> bind(final Function<A, StateMonad<S, B>> famb) {
return new StateMonad<S, B>((S s) -> {
Scp<S, A> currentPair = this.s2scp(s);
return famb(currentPair.content).s2scp(currentPair.state);
});
}
bind는 이기종 상태 모나드의 연결을 허용하고이 모나드와 다른 모나드에 계산을 유형에서 유형으로 이동할 수있는 놀라운 기능을 제공하기 때문에 제네릭 유형 B를 도입해야합니다.
여기서는 Java 코드로 멈출 것입니다. 복잡한 것은 GitHub 프로젝트에 있습니다. 이전 Java 버전과 비교할 때 람다는 많은 중괄호를 제거하지만 구문은 여전히 상당히 복잡합니다.
제쳐두고, 유사한 상태 모나드 코드가 다른 주류 언어로 작성되는 방법을 보여주고 있습니다. 스칼라의 경우, 바인드 (이 경우에 해야한다 라고 flatMap는 )처럼 읽고
def flatMap[A, B](famb: A => State[S, B]) = new State[S, B]((s: S) => {
val (ss: S, aa: A) = this.s2scp(s)
famb(aa).s2scp(ss)
})
JavaScript의 bind는 제가 가장 좋아하는 것입니다. 100 % 기능성, 가늘고 평균적이지만 물론 유형이 없습니다.
var bind = function(famb){
return state(function(s) {
var a = this(s);
return famb(a.value)(a.state);
});
};
<shameless> 여기서 몇 가지 모서리를 잘라 내고 있지만 세부 사항에 관심이 있다면 내 WP 블로그에서 찾을 수 있습니다. </ shameless>