2016-12-01 17 views
6

Theo đường ống mặc định được kéo dựa. Điều này là do các nhà điều hành >-> được thực hiện thông qua +>> là nhà điều hành quan trọng bind cho danh mục kéo của mình. Hiểu biết của tôi là điều này có nghĩa là nếu bạn có mã số như producer >-> consumer, cơ thể của người tiêu dùng sẽ được gọi trước, sau đó khi dữ liệu đang chờ dữ liệu, nhà sản xuất sẽ được gọi.Làm thế nào để biến một ống kéo dựa vào một đẩy dựa?

Tôi đã nhìn thấy trong tài liệu hướng dẫn pipeshere mà bạn có thể sử dụng mã (reflect .) từ Pipes.Core để biến một ống dựa kéo vào một ống dựa push. Điều đó có nghĩa là thay vào đó (sửa tôi nếu tôi sai) trong đoạn mã trên producer >-> consumer, nhà sản xuất được chạy đầu tiên, tạo ra một giá trị, sau đó người tiêu dùng cố gắng tiêu thụ. Điều đó có vẻ thực sự hữu ích và tôi muốn biết làm thế nào để làm điều đó.

Tôi cũng thấy trong các cuộc thảo luận here rằng không có đối tác dựa trên push để >-> vì nó rất dễ dàng để biến bất kỳ đường ống xung quanh (tôi giả định với phản ánh?), Nhưng tôi không thể thực sự con số làm thế nào để làm điều đó hoặc tìm bất kỳ ví dụ nào.

Dưới đây là một số mã tôi đã cố gắng:

stdin :: Producer String IO r 
stdin = forever $ do 
    lift $ putStrLn "stdin" 
    str <- lift getLine 
    yield str 

countLetters :: Consumer String IO r 
countLetters = forever $ do 
    lift $ putStrLn "countLetters" 
    str <- await 
    lift . putStrLn . show . length $ str 

-- this works in pull mode 
runEffect (stdin >-> countLetters) 

-- equivalent to above, works 
runEffect ((\() -> stdin) +>> countLetters) 

-- push based operator, doesn't do what I hoped 
runEffect (stdin >>~ (\_ -> countLetters)) 

-- does not compile 
runEffect (countLetters >>~ (\() -> stdin)) 

Trả lời

2
-- push based operator, doesn't do what I hoped 
runEffect (stdin >>~ (\_ -> countLetters)) 

tôi thu thập các vấn đề ở đây là, trong khi các nhà sản xuất đang chạy đầu tiên như mong đợi, giá trị sản xuất đầu tiên được giảm. Hãy so sánh ...

GHCi> runEffect (stdin >-> countLetters) 
countLetters 
stdin 
foo 
3 
countLetters 
stdin 
glub 
4 
countLetters 
stdin 

... với:

GHCi> runEffect (stdin >>~ (\_ -> countLetters)) 
stdin 
foo 
countLetters 
stdin 
glub 
4 
countLetters 
stdin 

Vấn đề này sẽ được thảo luận một cách chi tiết bởi Gabriel Gonzalez' câu trả lời cho this question. Nó tóm tắt cách đối số cho hàm mà bạn cung cấp cho (>>~) là đầu vào "lái xe" trong luồng dựa trên đẩy, và vì vậy nếu bạn const nó đi, bạn sẽ làm giảm đầu vào đầu tiên. Giải pháp là để định hình lại countLetters phù hợp:

countLettersPush :: String -> Consumer String IO r 
countLettersPush str = do 
    lift $ putStrLn "countLetters" 
    lift . putStrLn . show . length $ str 
    str' <- await 
    countLettersPush str' 
GHCi> runEffect (stdin >>~ countLettersPush) 
stdin 
foo 
countLetters 
3 
stdin 
glub 
countLetters 
4 
stdin 

Tôi cũng thấy trong các cuộc thảo luận here rằng không có push trụ sở đối tác để >-> vì nó rất dễ dàng để biến bất kỳ ống xung quanh (tôi giả sử với phản ánh?)

Tôi không hoàn toàn chắc chắn về mặt bằng của mình, nhưng có vẻ như không áp dụng cho giải pháp ở trên.Những gì chúng ta thể làm, bây giờ mà chúng tôi có dòng chảy đẩy dựa trên hoạt động chính xác, đang sử dụng reflect để biến nó xung quanh trở lại với một dòng chảy pull:

-- Preliminary step: switching to '(>~>)'. 
stdin >>~ countLettersPush 
(const stdin >~> countLettersPush)() 

-- Applying 'reflect', as the documentation suggests. 
reflect . (const stdin >~> countLettersPush) 
reflect . const stdin <+< reflect . countLettersPush 
const (reflect stdin) <+< reflect . countLettersPush 

-- Rewriting in terms of '(+>>)'. 
(reflect . countLettersPush >+> const (reflect stdin))() 
reflect . countLettersPush +>> reflect stdin 

Đây thực sự là kéo-based, như dòng chảy được thúc đẩy bởi reflect stdin, hạ lưu Client:

GHCi> :t reflect stdin 
reflect stdin :: Proxy String()() X IO r 
GHCi> :t reflect stdin :: Client String() IO r 
reflect stdin :: Client String() IO r :: Client String() IO r 

dòng chảy, tuy nhiên, liên quan đến việc gửi String s thượng nguồn, và vì vậy nó không thể được biểu diễn dưới dạng (>->), đó là, như vậy để nói, hạ lưu chỉ:

GHCi> -- Compare the type of the second argument with that of 'reflect stdin' 
GHCi> :t (>->) 
(>->) 
    :: Monad m => 
    Proxy a' a() b m r -> Proxy() b c' c m r -> Proxy a' a c' c m 
Các vấn đề liên quan