2017-11-27 4 views
9

나는 WAI 인터페이스를 흥미롭게 보았고 단순 해 보이지만 현재의 형태로 안정화하는데 얼마나 많은 반복이 필요한지를보고 놀랐다.WAI 어플리케이션을 5 번 재 설계 한 이유는 무엇입니까?

저는 리소스 안전을위한 CPS 스타일이 가장 흥미로운 것이라 가정했지만, 배울 점이 많습니다.

$ git log -p --reverse -- wai/Network/Wai.hs | grep '\+type Application' 
+type Application = Request -> Iteratee B.ByteString IO Response 
+type Application = Request -> ResourceT IO Response 
+type Application = Request -> C.ResourceT IO Response 
+type Application = Request -> IO Response 
+type Application = Request -> (forall b. (Response -> IO b) -> IO b) 
+type Application = Request -> (Response -> IO ResponseReceived) 
          -> IO ResponseReceived 

일부 고고학 수익률이 다소 만족스럽지 못한 결과 :

$ git log --reverse -G 'type Application' --pretty=oneline -- wai/Network/Wai.hs | cat 
879d4a23047c3585e1cba4cdd7c3e8fc13e17592 Moved everything to wai subfolder 
360442ac74f7e79bb0e320110056b3f44e15107c Began moving wai/warp to conduit 
af7d1a79cbcada0b18883bcc5e5e19a1cd06ae7b conduit 0.3 
fe2032ad4c7435709ed79683acac3b91110bba04 Pass around an InternalState instead of living in ResourceT 
63ad533299a0a5bad01a36171d98511fdf8d5821 Application uses bracket pattern 
1e1b8c222cce96c3d58cd27318922c318642050d ResponseReceived, to avoid existential issues 
+0

나는 재 설계 뒤에 * 힘 *을 주장하는 유혹을받을 수있다. – Carl

답변

4

모든 디자인은 세 가지 주요 관심사에 의해 구동 될 것으로 보인다 :

  • 요청 기관 (우리가하지 않는 스트리밍 가질 수 처리하기 전에 메모리에 모두로드해야 함). 가장 잘 표현하는 방법은 무엇입니까?
  • 응답을 스트리밍 할 수도 있습니다. 가장 잘 표현하는 방법은 무엇입니까?
  • 응답 생성시 할당 된 리소스를 올바르게 해제하는 방법은 무엇입니까? (예를 들어, 확인하는 방법이 파일 핸들? 파일을 처리 한 후 해제된다)

type Application = Request -> Iteratee B.ByteString IO Response 

This version 하스켈 스트리밍 데이터를위한 초기 해법 iteratees을 사용한다. Iteratee 소비자는 현대적인 스트리밍 라이브러리에서 사용되는 "끌어 당기는 사람"소비자보다 논리적으로 덜 자연스러운 "푸시 기반"방식으로 작성되어야했습니다.

요청의 스트리밍 된 본문이 iteratee에 공급되고 끝에 Response 값이 표시됩니다. Response에는 열거 자 (스트리밍 된 응답 바이트를 서버에서 제공하는 응답 반복자에 제공하는 함수)가 들어 있습니다. 아마도 열거자는 bracket과 같은 함수를 사용하여 리소스 할당을 제어합니다.


type Application = Request -> ResourceT IO Response 

This version

열거하는 대신에하기의 자원 관리를위한 모나드 resourcet 트랜스포머를 사용한다. 특수 문자 Source은 모두 RequestResponse으로 스트리밍 된 데이터를 처리합니다 (IMHO를 약간 이해하기 어렵습니다).


type Application = Request -> IO Response 

이 버전은 conduit에서 스트리밍 추상화를 사용하지만 resourcet을 피하고 대신 스트리밍 응답 자원을 처리하기위한 브라켓과 같은 responseSourceBracket 기능을 제공합니다. 자원 할당을 제어하기 위해 정기적 bracket -like 기능을 사용하기 위해 처리기 기능을 가능하게하는 연속 기반 접근법


type Application = Request -> (forall b. (Response -> IO b) -> IO b) 
type Application = Request -> (Response -> IO ResponseReceived) -> IO ResponseReceived 

This version 이동한다. 그 점에서 정사각형으로 돌아 가세요!

도관은 더 이상 스트리밍에 사용되지 않습니다.이제 요청 본문 청크를 읽기위한 일반 Request -> IO ByteStringfunction 및 응답 스트림 생성을위한 Response(Builder -> IO()) -> IO() -> IO()function이 있습니다.

iteratee 기반 버전과 달리 resourcet 기반 버전과 마찬가지로이 구현을 사용하면 응답을 스트리밍하면서 요청 본문을 겹쳐 읽을 수 있습니다.

다형 핸들러는 응답 수신 콜백 Response -> IO b이 항상 호출되도록 보장합니다. 핸들러는 b을 반환해야하며, 실제로는 콜백을 호출하는 유일한 방법입니다.

이 다형성 솔루션은 다형성을 사용하는 대신 공공 생성자없이 ResponseReceived 토큰을 사용할 수 있습니다. 효과는 같습니다. 핸들러 코드가 반환해야하는 토큰을 유지하는 유일한 방법은 콜백을 호출하는 것입니다.