I just want to mention that the `foldl` library already has a type that is similar to a `Transduction`: the `Handler` type, which is one type of "lens":

type Handler a b = forall x. (b -> Constant (Endo x) b) -> a -> Constant (Endo x) a

... and the `handles` function, which converts it to a function between `Fold`s:

    handles :: Handler a b -> Fold b r -> Fold a r
    handles k (Fold step begin done) = Fold step' begin done
      where
step' = flip (appEndo . getConstant . k (Constant . Endo . flip step))

This means that every lens that type-checks as a `Handler` is a transducer for free. For example:

    handles _1        :: Fold a b -> Fold (a, x)    b
    handles _Just     :: Fold a b -> Fold (Maybe a) b
    handles _traverse :: Fold a b -> Fold [a]       b

The easy way to reason about how this type works is to write the `Handler` type as the following isomorphic type:

    type Handler a b ≅forall x . (x -> b -> x) -> (x -> a -> x)

In other words, a `Handler` is just a transformation of a `Fold`'s step function. In theory this means that a `Handler` is almost as powerful as the `Transduction` type. The one thing the `Handler` cannot do is transform the `Fold`'s initial state (i.e. the "begin" field). Note that the `Handler` also cannot transform the `done` function, but neither can `Transduction` (because of parametricity).

It's not clear to me whether `Handler` is as powerful as the `Transducer` type, but I'm guessing that it is not.

Also, it's totally fine if you use `foldl-transduce`. I wasn't planning on using that module name and I'm creative at naming things anyway in the presence of name conflicts.

On 8/23/2015 3:47 AM, Daniel Díaz wrote:
Hi,

I was watching Rich Hickey's presentations on transducers and decided to implement something like it for foldl folds, as an exercise.

The repo is here: https://github.com/danidiaz/foldl-transduce

    import qualified Control.Foldl as L
    import Control.Foldl.Transduce
    import Control.Foldl.Transduce.Text

The main types are

    type Transduction a b = forall x. Fold b x -> Fold a x

    data Transducer i o r
         = forall x. Transducer (x -> i -> (x,[o])) x (x -> (r,[o]))

A Transducer is like a Fold that can emit output downstream. A Transducer can be applied to a Fold with the "transduce" function:

    transduce :: Transducer i o r -> Transduction i o

A very simple Transducer is "surround" that adds a prefix and a suffix to the stream of data coming to a Fold:

    >>> L.fold (transduce (surround "prefix" "suffix") L.list) "middle"
    "prefixmiddlesuffix"

Then there's also decoding transducers:

>>> L.fold (transduce utf8lenient L.list) (map fromString ["decode","this"])
    ["decode","this"]

And also transducer analogues of some functions from pipes-group (they're less powerful though, in that they force you to treat every group the same way):

>>> L.fold (groups (chunksOf 2) (transduce (surround [] [0])) L.list) [1..7]
    [1,2,0,3,4,0,5,6,0,7,0]

The existence of pipes makes transducers a bit superflous I suppose. Anyway, once I add some tests and iron out the (very likely) space leaks, I was thinking of putting this on Hackage as foldl-transduce (if Gabriel doesn't mind, I don't want to "name squat" on the foldl-* namespace.)

Any comments or bug reports welcome!
--
You received this message because you are subscribed to the Google Groups "Haskell Pipes" group. To unsubscribe from this group and stop receiving emails from it, send an email to haskell-pipes+unsubscr...@googlegroups.com <mailto:haskell-pipes+unsubscr...@googlegroups.com>. To post to this group, send email to haskell-pipes@googlegroups.com <mailto:haskell-pipes@googlegroups.com>.

--
You received this message because you are subscribed to the Google Groups "Haskell 
Pipes" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to haskell-pipes+unsubscr...@googlegroups.com.
To post to this group, send email to haskell-pipes@googlegroups.com.

Reply via email to