2017-02-23 8 views
4

Il ya un fil archivé sur reddit qui dit essentiellement que les conduits/tuyaux ne peuvent pas être des flèches b/c les flèches doivent être synchrones. Le fil est lié ici https://www.reddit.com/r/haskell/comments/rq1q5/conduitssinks_and_refactoring_arrows/Pourquoi Conduit et Pipe ne peuvent-ils pas avoir une instance Arrow?

Je ne vois pas où le « synchrone » viennent en tant que ne fait pas partie de la définition des flèches. De plus, je suis tombé sur ce projet sur github https://github.com/cmahon/interactive-brokers qui traite les tuyaux explicitement comme des flèches. Je colle l'instance def ici pour votre commodité. Qu'est-ce que j'oublie ici?

-- The code in this module was provided by Gabriel Gonzalez 

{-# LANGUAGE RankNTypes #-} 

module Pipes.Edge where 

import   Control.Arrow 
import   Control.Category (Category((.), id)) 
import   Control.Monad ((>=>)) 
import   Control.Monad.Trans.State.Strict (get, put) 
import   Pipes 
import   Pipes.Core (request, respond, (\>\), (/>/), push, (>~>)) 
import   Pipes.Internal (unsafeHoist) 
import   Pipes.Lift (evalStateP) 
import   Prelude hiding ((.), id) 

newtype Edge m r a b = Edge { unEdge :: a -> Pipe a b m r } 

instance (Monad m) => Category (Edge m r) where 
    id = Edge push 
    (Edge p2) . (Edge p1) = Edge (p1 >~> p2) 

instance (Monad m) => Arrow (Edge m r) where 
    arr f = Edge (push />/ respond . f) 
    first (Edge p) = Edge $ \(b, d) -> 
     evalStateP d $ (up \>\ unsafeHoist lift . p />/ dn) b 
     where 
     up() = do 
      (b, d) <- request() 
      lift $ put d 
      return b 
     dn c = do 
      d <- lift get 
      respond (c, d) 

instance (Monad m) => ArrowChoice (Edge m r) where 
    left (Edge k) = Edge (bef >=> (up \>\ (k />/ dn))) 
     where 
      bef x = case x of 
       Left b -> return b 
       Right d -> do 
        _ <- respond (Right d) 
        x2 <- request() 
        bef x2 
      up() = do 
       x <- request() 
       bef x 
      dn c = respond (Left c) 

runEdge :: (Monad m) => Edge m r a b -> Pipe a b m r 
runEdge e = await >>= unEdge e 
+0

est-ce que cela satisfait 'arr (f >>> g) = arr f >>> arr g'? Je soupçonne que non, mais je ne suis pas sûr – hao

+0

Ceci est induit par l'axiome de la catégorie, n'est-ce pas? – user2812201

+0

[Ce message de Gabriel Gonzalez] (https://groups.google.com/d/msg/haskell-pipes/H6YdVhyNksk/xr4NAPHzT2UJ) fournit des commentaires supplémentaires sur les instances pour les canaux basés sur des push que vous avez cités. – duplode

Répondre

4

Envisagez ce canal: yield '*' :: Pipe x Char IO(). Nous pourrions envelopper dans un nouvel adaptateur de type comme newtype PipeArrow a b = PipeArrow { getPipeArrow :: Pipe a b IO() } et essayer de définir l'instance Arrow là.

Achetez comment écrire un first :: PipeArrow b c -> PipeArrow (b, d) (c, d) qui fonctionne sur yield '*'? Le tuyau n'attend jamais une valeur de l'amont. Nous devrions produire un d hors de l'air, pour accompagner le '*'.

Les tubes satisfont la plupart des lois pour les flèches (et pour ArrowChoice) mais first ne peuvent pas être mis en œuvre de manière légale.

Le code que vous avez défini ne définit pas une int Arrow pour Pipe, mais pour une fonction qui prend une valeur en amont et renvoie un Pipe.

+2

Une [pièce d'accompagnement] (https://www.paolocapriotti.com/blog/2012/02/04/monoidal-instances-for-pipes/) à cette bonne réponse. – duplode