Free monad와 Reactive Extensions는 어떤 관련이 있습니까?


14

나는 LINQ가 Rx.NET으로 발전한 C # 배경에서 왔지만 항상 FP에 관심이있었습니다. F #에서 모나드와 사이드 프로젝트에 대한 소개를 한 후 다음 단계로 넘어갈 준비가되었습니다.

이제 스칼라 사람들의 무료 모나드에 대한 몇 가지 대화와 Haskell 또는 F #에서 여러 번의 글을 읽은 후, 이해력이있는 문법이 IObservable체인 과 매우 유사하다는 것을 알았습니다 .

FRP에서는 체인 내부에 남아있는 부작용 및 장애를 포함하여 더 작은 도메인 별 청크에서 작업 정의를 작성하고 응용 프로그램을 일련의 작업 및 부작용으로 모델링합니다. 무료 모나드에서, 내가 올바르게 이해한다면, 당신은 펑터로 작업을 만들고 코 요네 다를 사용하여 들어 올리는 방식으로 작업을 수행합니다.

어떤 접근 방식으로 바늘을 기울이는 것의 차이점은 무엇입니까? 서비스 나 프로그램을 정의 할 때 근본적인 차이점은 무엇입니까?


2
여기에 문제에 대해 생각하는 흥미로운 방법이있다 ... FRP는 모나드로 볼 수있다, 그것은 일반적 방법으로 공식화되지 않은 경우에도 . 대부분의 (모두는 아니지만) 모나드는 자유 모나드에 대해 동형 입니다. 으로 Cont(가) 단지, 하나는 아마 FRP 될 수 가정 할 수 있습니다 나는 자유 모나드를 통해 표현 될 수없는 제안 보았다 모나드이다. 거의 다른 무엇이든 할 수 있습니다 .
Jules

2
LINQ와 Rx.NET의 디자이너 인 Erik Meijer에 따르면 IObservable연속 모나드의 인스턴스입니다.
Jörg W Mittag 2018 년

1
지금은 세부 사항을 해결할 시간이 없지만 RX 확장과 무료 모나드 접근 방식은 모두 비슷한 목표를 달성 하지만 구조가 약간 다를 수 있습니다. RX Observables 자체가 모나드 일 수 있으며, 관찰 가능한 것을 사용하여 무료 모나드 계산을 매핑 할 수 있습니다. 이는 "free monad"의 "free"가 의미하는 바와 거의 같습니다. 또는 관계가 그렇게 직접적이지 않고 비슷한 목적으로 사용되는 방식을 선택하고 있습니다.
Tikhon Jelvis

답변:


6

모나드

모나드 구성

  • endofunctor . 소프트웨어 엔지니어링 세계에서는 이것이 제한되지 않은 단일 유형 매개 변수를 가진 데이터 유형에 해당한다고 말할 수 있습니다. C #에서는 다음과 같은 형식입니다.

    class M<T> { ... }
    
  • 해당 데이터 유형에 대해 정의 된 두 가지 조작 :

    • return/ pure는 "순수한"값 (즉, T값)을 가져 와서 모나드로 "랩핑"합니다 (즉, M<T>값을 생성 함 ). returnC #에서 예약 키워드 이므로 앞으로이 pure작업을 참조하는 데 사용하겠습니다 . C #에서는 다음 pure과 같은 서명이있는 메소드가됩니다.

      M<T> pure(T v);
      
    • bind/ flatmap는 monadic 값 ( M<A>)과 함수를 취 합니다 f. f순수한 값을 가져와 모나드 값 ( M<B>)을 반환합니다 . 이로부터 bind새로운 모나 딕 값 ( M<B>)이 생성됩니다. bind다음 C # 서명이 있습니다.

      M<B> bind(M<A> mv, Func<A, M<B>> f);
      

또한 모나드가 pure되고bind 세 개의 모나드의 법을 준수해야합니다.

이제 C #에서 모나드를 모델링하는 한 가지 방법은 인터페이스를 구성하는 것입니다.

interface Monad<M> {
  M<T> pure(T v);
  M<B> bind(M<A> mv, Func<A, M<B>> f);
}

(참고 : 일을 간략하고 표현력있게 유지하기 위해이 답변 전체에서 코드를 자유롭게 사용할 것입니다.)

이제 구체적인 구현을 구현하여 구체적인 데이터 기프에 대한 모나드를 구현할 수 있습니다 Monad<M>. 예를 들어 다음과 같은 모나드를 구현할 수 있습니다 IEnumerable.

class IEnumerableM implements Monad<IEnumerable> {
  IEnumerable<T> pure(T v) {
    return (new List<T>(){v}).AsReadOnly();
  }

  IEnumerable<B> bind(IEnumerable<A> mv, Func<A, IEnumerable<B>> f) {
    ;; equivalent to mv.SelectMany(f)
    return (from a in mv
            from b in f(a)
            select b);
  }
}

LINQ 구문과 모나드 간의 관계를 호출하기 위해 의도적으로 LINQ 구문을 사용하고 있습니다. 그러나 LINQ 쿼리를에 대한 호출로 바꿀 수 SelectMany있습니다.

이제 모나드를 정의 할 수 IObservable있습니까? 그렇게 보일 것입니다 :

class IObservableM implements Monad<IObservable> {
  IObservable<T> pure(T v){
    Observable.Return(v);
  }

  IObservable<B> bind(IObservable<A> mv, Func<A, IObservable<B>> f){
    mv.SelectMany(f);
  }
}

모나드가 있는지 확인하려면 모나드 법칙을 증명해야합니다. 이것은 사소한 일이 아니며 (Rx.NET이 사양만으로도 입증 될 수 있는지 여부를 알기에 충분하지는 않습니다) 유망한 시작입니다. 이 논의의 나머지 부분을 용이하게하기 위해,이 경우 모나드 법칙이 유지한다고 가정 해 봅시다.

무료 모나드

단수의 "무료 모나드"는 없습니다. 오히려, 무료 모나드는 펑터로 구성된 모나드 클래스입니다. , 펑터 주어 즉 F, 우리의 모나드 파생 자동으로 할 수 있습니다 F(즉,의 무료 모나드를F )를 .

펑터

모나드와 마찬가지로 펑 터는 다음 세 가지 항목으로 정의 할 수 있습니다.

  • 무제한의 단일 유형 변수에 대해 매개 변수화 된 데이터 유형.
  • 두 가지 작업 :

    • purefunctor에 순수한 가치를 담습니다. 이것은 pure모나드와 유사합니다 . 실제로 모나드이기도 한 펑터의 경우 두 개가 동일해야합니다.
    • fmap주어진 함수를 통해 입력 값을 출력의 새 값에 매핑합니다. 서명은 다음과 같습니다.

      F<B> fmap(Func<A, B> f, F<A> fv)
      

모나드와 마찬가지로 펑 터는 펑터 법을 준수해야합니다.

모나드와 유사하게 다음 인터페이스를 통해 펑터를 모델링 할 수 있습니다.

interface Functor<F> {
  F<T> pure(T v);
  F<B> fmap(Func<A, B> f, F<A> fv);
}

이제 모나드는 functors의 하위 클래스이므로 Monad약간 리팩터링 할 수도 있습니다 .

interface Monad<M> extends Functor<M> {
  M<T> join(M<M<T>> mmv) {
    Func<T, T> identity = (x => x);
    return mmv.bind(x => x); // identity function
  }

  M<B> bind(M<A> mv, Func<A, M<B>> f) {
    join(fmap(f, mv));
  }
}

여기에 추가로 방법을 추가 한 join, 모두의 기본 구현 제공 joinbind. 그러나 이들은 원형 정의입니다. 따라서 적어도 하나 이상을 재정의해야합니다. 또한 pure이제는에서 상속됩니다 Functor.

IObservable 그리고 무료 모나드

이제 모나드에 대해 모나드를 정의 IObservable했으므로 모나드는 functors의 하위 클래스이므로에 대한 functor 인스턴스를 정의 할 수 있어야합니다 IObservable. 여기 하나의 정의가 있습니다 :

class IObservableF implements Functor<IObservable> {
  IObservable<T> pure(T v) {
    return Observable.Return(v);
  }

  IObservable<B> fmap(Func<A, B> f, IObservable<A> fv){
    return fv.Select(f);
  }
}

에 대한 functor가 정의 IObservable되었으므로 해당 functor에서 무료 모나드를 생성 할 수 있습니다. 이것이 바로 IObservable무료 모나드와 어떻게 관련이 있는지 , 즉 우리는에서 무료 모나드를 구성 할 수 있다는 것입니다 IObservable.


범주 이론에 대한 통찰력있는 이해! 나는 그것들이 어떻게 만들어 졌는지에 대해 이야기하지 않았고, 기능적 아키텍처를 구축 할 때의 차이점과 그 중 하나를 사용하여 효과 구성을 모델링하는 것에 대해 이야기했습니다. FreeMonad는 통합 작업을 위해 DSL을 구축하는 데 사용될 수 있지만 IObservable은 시간이 지남에 따라 이산 값에 관한 것입니다.
MLProgrammer-CiM

1
@ MLProgrammer-CiM, 앞으로 며칠 안에 통찰력을 추가 할 수 있는지 살펴 보겠습니다.
Nathan Davis

나는 무료 모나드의 실제적인 예를 좋아합니다
l --''''''--------- '' '' '' '' '' '' ''22:
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.