avh4-experimental / elm-transducers / Transducer

A transducer is a composable way of processing a series of values. Many basic transducers correspond to functions you may be familiar with for processing Lists.

import Maybe
import String
import Transducer exposing (..)

parseValidInts =
    map String.toInt
        |> composeWith (map toMaybe)
        |> composeWith (filter ((/=) Nothing))
        |> composeWith (map (Maybe.withDefault 0))

exampleList : List Int
exampleList =
    transduceList parseValidInts [ "123", "-34", "35.0", "SDF", "7" ]

Definitions


type alias Reducer input result =
input -> result -> result

A reducer is a function taking an input and a value and produces a new value.

List.foldl : Reducer a b -> b -> List a -> b


type alias Transducer a b r state =
{ init : Reducer b r -> r -> ( state
, r )
, step : Reducer b r -> Reducer a ( state
, r )
, complete : Reducer b r -> ( state
, r ) -> r 
}

A transducer an init value for it's internal state, a step function that transforms a Reducer into a Reducer of a new type, and a complete function that transforms a Reducer into a function collapsing the internal state.

When defining transducers, the type parameter r should be left free.


type alias Fold input result source =
Reducer input result -> result -> source -> result

A fold is function that takes a Reducer, an initial value, and input source, and returns a final value.

Common transducers

map : (a -> b) -> Transducer a b r ()

Apply a function to every value.

transduceList (map sqrt) [ 1, 4, 9 ] == [ 1, 2, 3 ]

filter : (a -> Basics.Bool) -> Transducer a a r ()

Keep only values that satisfy the predicate.

transduceList (filter isEven) (List.range 1 6) == [ 2, 4, 6 ]

take : Basics.Int -> Transducer a a r Basics.Int

Take the first n values.

transduceList (take 2) [ 1, 2, 3, 4 ] == [ 1, 2 ]

drop : Basics.Int -> Transducer a a r Basics.Int

Drop the first n values.

transduceList (drop 2) [ 1, 2, 3, 4 ] == [ 3, 4 ]

More transducers

concatMap : (a -> List b) -> Transducer a b r ()

Map a given function onto a list and flatten the results.

transduceList (concatMap (\x -> [ x, x + 10 ])) [ 1, 2 ] == [ 1, 10, 2, 20 ]

dedupe : Transducer a a r (Maybe a)

Drop values that repeat the previous value.

transduceList dedupe [ 1, 1, 2, 2, 1 ] == [ 1, 2, 1 ]

partition : Basics.Int -> Transducer a (List a) r ( Basics.Int, List a )

Group a series of values into Lists of size n.

transduceList (partition 2) [ 1, 2, 3, 4, 5 ] == [ [ 1, 2 ], [ 3, 4 ], [ 5 ] ]

Composing transducers

composeWith : Transducer b c r s2 -> Transducer a b ( s2, r ) s1 -> Transducer a c r ( s1, s2 )

Compose two transducers.

firstOperation
    |> composeWith secondOperation

Applying transducers

transduce : Fold a ( s, r ) x -> Reducer b r -> r -> Transducer a b r s -> x -> r

Apply a transducer.

transduceList : Transducer a b (List b) s -> List a -> List b

Apply a Transducer to a List, producing a List.

transduceList t xs == transduce List.foldr (::) [] t xs

transduceSet : Transducer a comparable (Set comparable) s -> Set a -> Set comparable

Apply a Transducer to a Set, producing a Set.

transduceSet t xs =
    transduce Set.foldr Set.insert Set.empty t xs

transduceArray : Transducer a b (Array b) s -> Array a -> Array b

Apply a Transducer to an Array, producing an Array.

transduceArray t xs =
    transduce Array.foldl Array.push Array.empty t xs