Haskell Language
पाइप्स
खोज…
टिप्पणियों
हैकेज पेज का वर्णन के रूप में:
पाइप एक साफ और शक्तिशाली स्ट्रीम प्रोसेसिंग लाइब्रेरी है जो आपको पुन: प्रयोज्य स्ट्रीमिंग घटकों को बनाने और कनेक्ट करने देती है
स्ट्रीमिंग के माध्यम से कार्यान्वित किए जाने वाले कार्यक्रम अक्सर सरल और संक्षिप्त हो सकते हैं, हास्केल प्रकार प्रणाली के समर्थन के साथ सरल, छोटे फ़ंक्शन आपको "स्लॉट इन या आउट" सुविधाओं की अनुमति देते हैं।
await :: Monad m => Consumer' ama
अपस्ट्रीम से एक मान खींचता है, जहां a
हमारे इनपुट प्रकार है।
yield :: Monad m => a -> Producer' am ()
एक मान उत्पन्न करें, जहां a
आउटपुट प्रकार है।
यह अत्यधिक अनुशंसा की जाती है कि आप एम्बेडेड Pipes.Tutorial
माध्यम से पढ़ें। Pipes.Tutorial
पैकेज जो पाइप की मुख्य अवधारणाओं और Producer
, Consumer
और Effect
बातचीत का एक उत्कृष्ट अवलोकन देता है।
प्रोड्यूसर्स
एक Producer
कुछ विवादास्पद कार्रवाई है जो डाउनस्ट्रीम खपत के लिए मूल्य yield
कर सकता yield
:
type Producer b = Proxy X () () b
yield :: Monad m => a -> Producer a m ()
उदाहरण के लिए:
naturals :: Monad m => Producer Int m ()
naturals = each [1..] -- each is a utility function exported by Pipes
हम निश्चित रूप से Producer
कि अन्य मूल्यों के कार्य भी कर सकते हैं:
naturalsUntil :: Monad m => Int -> Producer Int m ()
naturalsUntil n = each [1..n]
उपभोक्ताओं
एक Consumer
केवल अपस्ट्रीम से मूल्यों का await
कर सकता है।
type Consumer a = Proxy () a () X
await :: Monad m => Consumer a m a
उदाहरण के लिए:
fancyPrint :: MonadIO m => Consumer String m ()
fancyPrint = forever $ do
numStr <- await
liftIO $ putStrLn ("I received: " ++ numStr)
पाइप्स
पाइप await
और yield
दोनों कर सकते हैं।
type Pipe a b = Proxy () a () b
यह पाइप एक Int
इंतजार करता है और इसे एक String
परिवर्तित करता है:
intToStr :: Monad m => Pipe Int String m ()
intToStr = forever $ await >>= (yield . show)
RunEffect के साथ रनिंग पाइप
हम अपने Pipe
को चलाने के लिए रन- runEffect
का उपयोग करते हैं:
main :: IO ()
main = do
runEffect $ naturalsUntil 10 >-> intToStr >-> fancyPrint
ध्यान दें कि runEffect
लिए एक Effect
आवश्यकता होती है, जो कि एक इनपुट या आउटपुट के साथ एक स्व-निहित Proxy
:
runEffect :: Monad m => Effect m r -> m r
type Effect = Proxy X () () X
(जहाँ X
खाली प्रकार है, जिसे Void
भी कहा जाता है)।
पाइपों को जोड़ना
बड़े Pipe
कार्यों की रचना करने के लिए Producer
, Consumer
और Pipe
को जोड़ने के लिए >->
का उपयोग करें।
printNaturals :: MonadIO m => Effect m ()
printNaturals = naturalsUntil 10 >-> intToStr >-> fancyPrint
Producer
, Consumer
, Pipe
, और Effect
प्रकार सभी सामान्य Proxy
प्रकार के संदर्भ में परिभाषित किए गए हैं। इसलिए >->
का उपयोग विभिन्न उद्देश्यों के लिए किया जा सकता है। बाएं तर्क द्वारा परिभाषित प्रकारों को सही तर्क द्वारा खपत प्रकार से मेल खाना चाहिए:
(>->) :: Monad m => Producer b m r -> Consumer b m r -> Effect m r
(>->) :: Monad m => Producer b m r -> Pipe b c m r -> Producer c m r
(>->) :: Monad m => Pipe a b m r -> Consumer b m r -> Consumer a m r
(>->) :: Monad m => Pipe a b m r -> Pipe b c m r -> Pipe a c m r
प्रॉक्सी मोनाड ट्रांसफार्मर
pipes
का मुख्य डेटा प्रकार Proxy
मोनाड ट्रांसफार्मर है। Pipe
, Producer
, Consumer
और इतने पर Proxy
संदर्भ में परिभाषित किया गया है।
चूंकि Proxy
एक मोनड ट्रांसफ़ॉर्मर है, इसलिए Pipe
परिभाषाएँ मोनैडिक स्क्रिप्ट्स का रूप लेती हैं जो मूल्यों का await
और yield
हैं, इसके अलावा बेस मोनड m
से प्रभाव प्रदर्शन करते हैं।
पाइप्स और नेटवर्क संचार का मेल
पाइप क्लाइंट और सर्वर के बीच सरल बाइनरी संचार का समर्थन करता है
इस उदाहरण में:
- एक ग्राहक कनेक्ट करता है और एक
FirstMessage
भेजता है - सर्वर
DoSomething 0
को प्राप्त करता है और उत्तर देता है - ग्राहक प्राप्त करता है और
DoNothing
जवाबDoNothing
- चरण 2 और 3 को अनिश्चित काल तक दोहराया जाता है
नेटवर्क पर एक्सचेंज किए गए कमांड डेटा प्रकार:
-- Command.hs
{-# LANGUAGE DeriveGeneric #-}
module Command where
import Data.Binary
import GHC.Generics (Generic)
data Command = FirstMessage
| DoNothing
| DoSomething Int
deriving (Show,Generic)
instance Binary Command
यहां, सर्वर एक क्लाइंट को कनेक्ट करने के लिए इंतजार करता है:
module Server where
import Pipes
import qualified Pipes.Binary as PipesBinary
import qualified Pipes.Network.TCP as PNT
import qualified Command as C
import qualified Pipes.Parse as PP
import qualified Pipes.Prelude as PipesPrelude
pageSize :: Int
pageSize = 4096
-- pure handler, to be used with PipesPrelude.map
pureHandler :: C.Command -> C.Command
pureHandler c = c -- answers the same command that we have receveid
-- impure handler, to be used with PipesPremude.mapM
sideffectHandler :: MonadIO m => C.Command -> m C.Command
sideffectHandler c = do
liftIO $ putStrLn $ "received message = " ++ (show c)
return $ C.DoSomething 0
-- whatever incoming command `c` from the client, answer DoSomething 0
main :: IO ()
main = PNT.serve (PNT.Host "127.0.0.1") "23456" $
\(connectionSocket, remoteAddress) -> do
putStrLn $ "Remote connection from ip = " ++ (show remoteAddress)
_ <- runEffect $ do
let bytesReceiver = PNT.fromSocket connectionSocket pageSize
let commandDecoder = PP.parsed PipesBinary.decode bytesReceiver
commandDecoder >-> PipesPrelude.mapM sideffectHandler >-> for cat PipesBinary.encode >-> PNT.toSocket connectionSocket
-- if we want to use the pureHandler
--commandDecoder >-> PipesPrelude.map pureHandler >-> for cat PipesBinary.Encode >-> PNT.toSocket connectionSocket
return ()
ग्राहक इस प्रकार जोड़ता है:
module Client where
import Pipes
import qualified Pipes.Binary as PipesBinary
import qualified Pipes.Network.TCP as PNT
import qualified Pipes.Prelude as PipesPrelude
import qualified Pipes.Parse as PP
import qualified Command as C
pageSize :: Int
pageSize = 4096
-- pure handler, to be used with PipesPrelude.amp
pureHandler :: C.Command -> C.Command
pureHandler c = c -- answer the same command received from the server
-- inpure handler, to be used with PipesPremude.mapM
sideffectHandler :: MonadIO m => C.Command -> m C.Command
sideffectHandler c = do
liftIO $ putStrLn $ "Received: " ++ (show c)
return C.DoNothing -- whatever is received from server, answer DoNothing
main :: IO ()
main = PNT.connect ("127.0.0.1") "23456" $
\(connectionSocket, remoteAddress) -> do
putStrLn $ "Connected to distant server ip = " ++ (show remoteAddress)
sendFirstMessage connectionSocket
_ <- runEffect $ do
let bytesReceiver = PNT.fromSocket connectionSocket pageSize
let commandDecoder = PP.parsed PipesBinary.decode bytesReceiver
commandDecoder >-> PipesPrelude.mapM sideffectHandler >-> for cat PipesBinary.encode >-> PNT.toSocket connectionSocket
return ()
sendFirstMessage :: PNT.Socket -> IO ()
sendFirstMessage s = do
_ <- runEffect $ do
let encodedProducer = PipesBinary.encode C.FirstMessage
encodedProducer >-> PNT.toSocket s
return ()