2013-10-08 2 views
2

Snap의 소스를 최근에 읽었습니다.이 기능은 훌륭합니다.하지만 Snaplet Handler 소스를 읽으려고 할 때 RST, Lensed 및 LensT의 추상화에 빠져들게되었습니다. ,Snapshot에서 RST, Lensed 및 LensT의 abstration을 이해하는 방법은 무엇입니까?

newtype RST r s m a = RST { runRST :: r -> s -> m (a, s) } 
newtype LensT b v s m a = LensT (RST (Lens b v) s m a) 
newtype Handler b v a = Handler (LensT (Snaplet b) (Snaplet v) (Snaplet b) Snap a) 

이제 LensT는 렌즈 효과

newtype Lensed b v m a = Lensed { unlensed :: ALens' b v -> v -> b -> m (a, v, b) } 

로 변경 그리고 Snaplet DesignWe switched to a slightly more specialized monad formulation called Lensed that avoids traversal of the whole state hierarchy when the state is manipulated.

내가 스냅 및 Snaplet 처리기의 구현 사이의 간격이 같은 느낌, 그리고 키가 RST입니다 말했다 LensT and Lensed, 나에게 도움이되는 참조 문서가 있습니까?

+2

'RST'는'Writer' 부분이없는'RWST'이며 효율성을 위해 제외되었습니다. http://hackage.haskell.org/package/mtl-2.1.2/docs/Control-Monad-RWS-Lazy.html#v:RWST을 참조하십시오. – Carl

답변

2

TL; DR - 간격이 없습니다. 붙여 넣은 핸들러 정의가 오래되었습니다. current one은 Lensed를 사용합니다.

긴 답변 : 저수준 구현 세부 정보이므로 여기에 대한 문서가 없습니다. 그것 모두는 최종 사용자로부터 완전히 숨겨져 있습니다. Carl이 RST가 단지 RWST에서 W를 뺀 것이 옳다는 것을 알았지 만 더 깊은 조사를 해봅시다. 위에 표시된 유형을 사용하여 RST의 정의를 LensT 정의로 대체합니다.

r = Lens b v 
s = s 
m = m 
a = a 
그와

우리가 할 수있는 쉽게 확장 LensT 정의 쓰기 : 렌즈 효과에 있음을

newtype LensT b v s m a = LensT { unlensT :: Lens b v -> s -> m (a, s) } 

비교를 :

newtype Lensed b v m a = Lensed { unlensed :: ALens' b v -> v -> b -> m (a, v, b) } 

것은 우리가 가정하면 그 Lens b v이 우리에게 다음과 같은 대체를 제공합니다 ALens' b v은 상호 교환 가능합니다 (개념적으로는 그것들입니다). 그러면 동등한 것을 볼 수 있습니다 :

Lensed b v m a = LensT b v (b,v) m a 

이제 우리는 문제의 핵심을 봅니다. LensT는 Lensed보다 일반적인 구조입니다. LensT를 사용하면 임의로 s을 선택할 수 있습니다. 수정 된 s 수정 프로그램은 bv에 의해 완전히 결정됩니다. 차이점을 이해 했으므로이 두 구문이 Snap에서 실제로 어떻게 사용되는지가 궁금합니다. Types.hs을 통한 빠른 grep은 Handler가 Lensed를 사용하고 Initializer가 LensT를 사용함을 보여줍니다. (사이드 노트 : 당신이 Handler를 위해 제공 한 정의는 우리가 현재 사용하고있는 정의가 아닙니다.) 정의의 중요한 부분은 다음과 같습니다. 그렇지 bv과 관련된 추가 정보를 포함 InitializerState, s 될 필요하기 때문에

Handler b v a = Handler (L.Lensed (Snaplet b) (Snaplet v) ...) 
Initializer b v a = Initializer (LT.LensT (Snaplet b) (Snaplet v) (InitializerState b)...) 

는 이니셜 더 일반적인 LensT 구조를 사용한다. 사실 Initializer가 존재한다는 요지는 핸들러의 초기 상태로 사용될 b의 생성을 용이하게하는 것입니다. 응용 프로그램이 시작될 때 Initializer가 실행되지만 Handler는 응용 프로그램이 실행되는 곳입니다. 우리는 Handler를 최대한 효율적으로 사용하기를 원했기 때문에 Handler의 요구에 맞게 Lensed를 만들었습니다. 조숙 한 최적화라고 주장 할 수는 있지만, 다른 누군가가 나를 위해 해준 이후로, 나는 아니오라고 말하지 않을 것입니다.

우리가 왜 Lensed와 LensT를 가지고 있는지 궁금해 할 것입니다. 그것들은 단지 하나의 장소에서만 사용되기 때문에 정의를 각각 Handler와 Initializer로 대체 할 수 있습니다.그것은 우리가 맨 처음에 렌즈를 가지고 있지 않았기 때문입니다. Handler와 Initializer는 모두 LensT로 작성되었으므로 중복 된 코드를 제거하는 것은 완벽하게 합리적인 추상화입니다. 어쨌든 렌즈 타입은 모든 newtype이기 때문에, 이러한 추상 레이어는 런타임 비용을 제로화합니다.