2017-02-05 17 views
1

저는 카테고리 이론을 배우고 있습니다. 나는 독자 모나드의 개념을 이해 , 그것을 구현하는 데에도 꽤 쉽게 :독자 모나드 - 모나드 인터페이스에 어떻게 부합합니까?

case class Reader[DEP, A](g: DEP => A) { 
    def apply(dep: DEP): A = g(dep) 

    def map[B](f: A => B): Reader[DEP, B] = Reader(dep => f(apply(dep))) 

    def flatMap[B](f: A => Reader[DEP, B]): Reader[DEP, B] = Reader(dep => f(apply(dep)) apply dep) 
} 

그러나, 나는 몇 가지 일반적인 모나드 인터페이스에 대한 제약 조건을 구현하는 문제가있다, 즉,하자가에 대한 잊었

trait Monad[A] { 
    def pure(a: A): Monad[A] 

    def map[B](f: A => B): Monad[B] 

    def flatMap[B](f: A => Monad[B]): Monad[B] 
} 

두 번째로 응용 자 또는 펑터 (functor)가 있으며,이 3 가지 방법을 여기에 넣자.

이제이 인터페이스를 사용하여 ReaderMonad를 구현하는 데 문제가 있습니다. 맵 메서드는 꽤 복잡하지만 순수하고 flatMap은 어떻습니까? 독자에게 순수한 의미는 무엇입니까? flatMap을 구현하려면 A부터 Reader [DEP, B]까지 함수가 있어야하지만 A => Monad [B]가 있으므로 적용 할 수 없습니다.

case class Reader[DEP, A](g: DEP => A) extends Monad[A] { 
    def apply(dep: DEP): A = g(dep) 

    override def pure(a: A): Reader[DEP, A] = Reader(_ => a) // what does it even mean in case of Reader 

    override def map[B](f: (A) => B): Reader[DEP, B] = Reader(dep => f(apply(dep))) 

    override def flatMap[B](f: (A) => Monad[B]): Reader[DEP, B] = ??? // to implement it, I need f to be (A) => Reader[DEP, B], not (A) => Monad[B] 
} 

이렇게하면 스칼라로 구현할 수 있습니까? 나는 셀프 바인딩 된 타입으로 놀려고했지만 그것도 작동하지 않았다. scalaz 또는 cats와 같은 라이브러리는 이러한 유형을 구현하기 위해 유형 클립을 사용하지만 이는 교육적인 목적을위한 것임을 알고 있습니다.

+0

기본 구현을 살펴보고 어떻게 사용하는지 살펴 보겠습니다. 하스켈을 아는 경우 (그리고 그렇지 않은 경우 라 할지라도) 단서를 찾기 위해 독자 Monad의 정의를 살펴볼 가치가 있습니다. – Carcigenicate

+0

글쎄, 그들은 완전히 다른 구문 (주로 typeclasses)을 사용하므로 도움이 될지 확신 할 수 없다. – slnowak

+0

이 문제의 주된 문제점은 '모나드'특성이 잘못되어 사용자가 발견 한대로 캐스팅하지 않으면 구현할 수 없다는 것이다. . 일반적인 구현은 타입 생성자로'Monad' 특성을 매개 변수화하고'Reader [DEP, _]'에 대해 정의하는 것입니다. – Lee

답변

2

flatMap을 구현할 때 발견 한 것처럼 Monad 특성을 선언 할 때의 문제는 연결 작업을 할 때 정의중인 특정 모나드 유형을 잃어 버리는 것입니다. Monad 특성을 정의하는 일반적인 방법은 모나드 인스턴스가 정의되고있는 유형 생성자로 매개 변수를 매개 변수화하는 것입니다.

trait Monad[M[_]] { 
    def pure[A](a: A): M[A] 
    def map[A, B](f: A => B, m: M[A]): M[B] 
    def flatMap[A, B](f: A => M[B], m : M[A]): M[B] 
} 

그래서 MList 또는 Option 같은 단항 타입 생성자이다. Reader[DEP, A]A 유형의 값을 리턴하는 일부 환경 유형 DEP에 종속 된 계산으로 간주 할 수 있습니다. 이 두 유형의 매개 변수를 가지고 있기 때문에 당신은 모나드 인스턴스를 정의 할 때 환경 매개 변수 유형을 수정해야합니다

case class Reader[DEP, A](g: DEP => A) 

class ReaderMonad[DEP]() extends Monad[({type t[X] = Reader[DEP, X]})#t] { 
    def pure[A](a: A) = Reader[DEP, A](_ => a) 
    def map[A, B](f: A => B,m: Reader[DEP,A]): Reader[DEP,B] = Reader(env => f(m.g(env))) 
    def flatMap[A, B](f: A => Reader[DEP,B],m: Reader[DEP,A]): Reader[DEP,B] = Reader(env => f(m.g(env)).g(env)) 
} 

({type t[X] = Reader[DEP, X]})#t 부분적으로 Reader[DEP, A]에 대한 두 개의 매개 변수 중 하나를 적용하는 데 사용되는 type lambda입니다.

이제 pure은 환경을 무시하고 주어진 값을 직접 반환하는 Reader을 반환합니다.

flatMap이 실행되면 내부 계산이 실행되고 결과를 사용하여 다음 계산을 구성하고 동일한 환경에서 실행합니다.

+0

고마워요! 그 유형 람다는 ... 적어도 흥미 롭습니다. – slnowak

+2

100K에 축하해! –

+0

@YuvalItzchakov - 감사합니다! – Lee