2016-12-01 6 views
6

デフォルトでは、パイプはプルベースです。これは、オペレータ>->+>>によって実装されているためです。これは、彼のプルカテゴリの点数がbindです。私が理解していることは、producer >-> consumerのようなコードがあれば、消費者の身体が最初に呼び出され、データを待ってからプロデューサが呼び出されるということです。プッシュベースのパイプをプッシュベースのパイプに変換するにはどうすればいいですか?

私はあなたがプッシュベースのパイプにプルベースのパイプをオンにするPipes.Coreからコード(reflect .)を使用することができますpipesドキュメントhereで見てきました。つまり、コードがproducer >-> consumerを超えると、プロデューサが最初に実行され、値が生成され、次にコンシューマが消費しようとします。それは本当に便利だと私はそれを行う方法を知りたいです。

私もそこに(私が仮定反映?)周りの任意のパイプを回すために簡単ですので、 >->へのプッシュベースの対応はありませんが、私は実際にそれを行う方法を見つけ出すことはできませんという議論 hereで見てきた

か例を見つける。私はプロデューサーが最初の予想通りに走っている間に、最初に生成される値が低下している、ということですここで問題を収集

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)) 

答えて

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

は、ここで私がしようとしてきたいくつかのコードです。

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

この問題はthis questionにガブリエル・ゴンザレス」と答えて詳細に説明しますと... ...

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

の比較。それは、あなたが(>>~)に与える関数への引数が、プッシュベースのフローの "駆動"入力であることにどのように結びついているのでしょうか。したがって、constそれを離れれば、最初の入力を落とします。解決策は、それに応じcountLettersを再構築することである:周りの任意のパイプを回すために簡単ですので、私はまた、議論hereで見てきた

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 

>->へのプッシュベースの対応が存在しないこと(I反射と仮定しますか?)

私は自分の考えを完全には分かりませんが、それは上記の解決策にはあまり当てはまりません。我々はは、今私たちが正しく動作プッシュベースのフローを持っていることを、何ができるバックプル型の流れにそれを好転させるためにreflectを使用している:

-- 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 

これはプル・ベースとして、確かにあります流れがreflect stdin、下流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 

流れが、下流側のみ、そう言うことであり、これは、上流String Sを送信し、そしてそれは(>->)で表現することができないことを含みます。

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 
関連する問題