2016-02-01 5 views
8

Kendi sum işlevimi yazarak pipes paketini öğrenmeye çalışıyorum ve stumped alıyorum. Yardımcı fonksiyonlarını Pipes.Prelude'dan (sum ve fold ve önemsiz kılan diğer işlevlere sahip olduğundan) kullanmak istemiyorum ve sadece bilgileri Pipes.Tutorial'da açıklandığı gibi kullanın. Öğretici Proxy yapıcıları hakkında konuşmuyor, ancak sum ve fold kaynağına baktığımda bu kurucuları kullanır ve bu düşük seviye ayrıntılarını bilmeden benim sum fonksiyonumu yazmanın mümkün olup olmadığını merak ediyorum.Haskell Boruları "toplamı" fonksiyonu nasıl yazılır?

Bu işlevin, değerler mevcut olduğu sürece değerleri almaya devam etmesini nasıl sağlayabileceğiyle ilgili tereddütler yaşıyorum ve sonra bu şekilde kullanıcıya toplamı iade ediyorum. Ben türü olacağını tahmin: Bu fonksiyon artık kalmayıncaya kadar sonra, değerleri tüketmek nihai toplamı geri dönebilirler çünkü bana görünen

sum' :: Monad m => Consumer Int m Int 

bu işe yarayabilir. Böyle kullanmak olacaktır:

mysum <- runEffect $ inputs >-> sum' 

Ancak Pipes.Prelude işlevi yerine aşağıdaki imzası vardır:

sum :: (Monad m, Num a) => Producer a m() -> m a 

Yani bu benim ilk engel sanırım. sum işlevi, bağlanmak için >-> kullanmak yerine, bir Producer numaralı argümanı neden alır?


Bilginize ben danidiaz gelen cevap sonrasında aşağıdaki ile sona erdi:

sum' = go 0 
    where 
    go n p = next p >>= \x -> case x of 
     Left _  -> return n 
     Right (_, p') -> go (n + 1) p' 
+0

'borularda sum' * * numaralar üreten ve Birli eylem bunları özetliyor şey alır ... düşüncesi oldukça benzer eğer düşünürseniz - aynı zamanda paket detaylara dikkat etmeyecek şekilde tasarlanmalıdır, ancak 'fold' ve sağlanan ilkellerin geri kalanını kullanmalısınız;) – Carsten

cevap

5

Consumers aslında oldukça neler yapabileceklerini sınırlıdır. Giriş bitimini algılayamazlar (pipes-parse bunun için farklı bir teknik kullanır) ve boru hattının başka bir kısmı durduğunda (örneğin Producer yukarı yönde)bubölümünün sonuç değerini vermesi gereken boru hattı. Yani toplamı, Consumer'un geri dönüş değerine koymak genel olarak işe yaramaz.

Bazı alternatif:

  • Producer iç yapıları doğrudan ilgilenir, ya da belki next gibi yardımcı bir işlev kullanan bir işlevi uygulamak. Bu türden Producer verilerini "akıllı" tüketicilere besleyebilen, s foldl paketinden besleyebilen adaptörler vardır. Bir Consumer, ancak bunun yerine Consumer dönüş değeri toplamı koyarak kullanılarak

  • tutun, akümülatör gibi bir Sum Int Monoid baz monadın olarak WriterT kullanın. Bu şekilde, Producer ilk önce dursa bile, yazara akümülatöre ulaşmak için hala koşabilirsiniz. Bu çözümün daha az verimli olması muhtemeldir.WriterT yaklaşım için

örnek kod: iyi

import Data.Monoid 
import Control.Monad 
import Control.Monad.Trans.Writer 
import Pipes 

producer :: Monad m => Producer Int m() 
producer = mapM_ yield [1..10] 

summator :: Monad n => Consumer Int (WriterT (Sum Int) n)() 
summator = forever $ await >>= lift . tell . Sum 

main :: IO() 
main = do 
    Sum r <- execWriterT . runEffect $ producer >-> summator 
    print r 
+0

"Giriş sonu tespit edilemedi" Ben kayıptı. Çok teşekkürler. – Ana