Skip to content

Instantly share code, notes, and snippets.

@davidglassborow
Forked from cloudRoutine/01_folds.fs
Created February 7, 2017 13:59
Show Gist options
  • Save davidglassborow/2c1a0ca7f50ae90bbae9e72a7bb7fbdc to your computer and use it in GitHub Desktop.
Save davidglassborow/2c1a0ca7f50ae90bbae9e72a7bb7fbdc to your computer and use it in GitHub Desktop.

Revisions

  1. @cloudRoutine cloudRoutine revised this gist Aug 18, 2015. 1 changed file with 2 additions and 3 deletions.
    5 changes: 2 additions & 3 deletions 02_transducers.fs
    Original file line number Diff line number Diff line change
    @@ -103,9 +103,8 @@ module Core =



    /// Concatting should always precede a reduction
    // concat IS a transducer as opposed to a function that returns a transducer
    let inline concat() =

    let inline concat =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    Folds.foldl stepfn acc input
  2. @cloudRoutine cloudRoutine created this gist Aug 18, 2015.
    341 changes: 341 additions & 0 deletions 01_folds.fs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,341 @@

    open System.Collections.Generic
    open Microsoft.FSharp.Collections


    [<RequireQualifiedAccess>]
    module Folds =

    // These are the fast implementations we actually want to use


    /// Tail-recursive left fold
    let inline foldl (stepfn:'b->'a->'b)(acc:'b)(coll:#seq<'a>) : 'b =
    use enumer = coll.GetEnumerator()
    let rec loop acc' =
    match enumer.MoveNext() with
    | false -> acc'
    | true -> loop ( stepfn acc' enumer.Current )
    loop acc


    let inline foldlpost (stepfn:'b->'a->'b)(postfn:'b->'c)(acc:'b)(coll:#seq<'a>) : 'c =
    use enumer = coll.GetEnumerator()
    let rec loop acc' =
    match enumer.MoveNext() with
    | false -> postfn acc'
    | true -> loop ( stepfn acc' enumer.Current )
    loop acc

    // let inline unfold
    // (stepfn)(acc)
    // (pred)(mapElm)(inc)(seed) =
    // let rec loop acc' state =
    // match pred state with
    // | false -> acc'
    // | true -> loop (stepfn acc' (mapElm state)) (inc state)
    // loop acc seed

    let inline unfold
    (stepfn:'c->'b->'c)(acc:'c)
    (pred:'a->bool)(mapElm:'a->'b)(inc:'a->'a)(seed:'a) : 'c =
    let rec loop acc' state =
    match pred state with
    | false -> acc'
    | true -> loop (stepfn acc' (mapElm state)) (inc state)
    loop acc seed

    /// Tail-recursive left unfold
    let inline unfoldlsl (pred:'a->bool)(mapElm:'a->'b)(inc:'a->'a)(seed:'a) : 'b list =
    let rec loop acc' state =
    match pred state with
    | false -> acc'
    | true -> loop (mapElm state::acc') (inc state)
    loop [] seed

    let inline unfoldls pred mapElm inc seed = unfoldlsl pred mapElm inc seed |> List.rev


    let inline unfoldpost
    (stepfn:'c->'b->'c) (acc:'c)
    (postfn:'c->'d)
    (pred:'a->bool)(mapElm:'a->'b)(inc:'a->'a)(seed:'a): 'd =
    let rec loop acc' state =
    match pred state with
    | false -> postfn acc'
    | true -> loop(stepfn acc' (mapElm state)) (inc state)
    loop acc seed




    // let hyloUnfold h f g = hylo h (f ) (unfold g)


    // TODO implement scan


    [<RequireQualifiedAccess>]
    module Left =

    let map ( f :'a->'b ) ( collection:#seq<'a> ) =
    foldl ( fun acc elm -> (f elm)::acc) [] collection

    let filter (pred:'a -> bool) (collection:#seq<'a>) =
    foldl ( fun acc elm -> if pred elm then elm::acc else acc ) [] collection

    let collect ( f :'a->'b list ) ( collection:#seq<'a> ) =
    let cons xs x = x::xs
    foldl ( fun acc elm -> foldl cons acc (f elm)) [] collection


    let take num (collection:#seq<'a>) =
    match num with
    | 0 -> []
    | x when x < 0 ->
    invalidArg "num" (sprintf "args for take must be postive, value passed in was %d" num )
    | _ ->
    use numer = collection.GetEnumerator()
    let rec loop (acc:'a list) (cnt:int) =
    match numer.MoveNext(), cnt < num-1 with
    | true, true -> loop (numer.Current::acc) (cnt+1)
    | _ -> acc
    match numer.MoveNext() with
    | true -> loop (numer.Current::[]) 0
    | false -> []


    let takeSafe num (collection:#seq<'a>) =
    match num with
    | x when x <= 0 -> []
    | _ ->
    use numer = collection.GetEnumerator()
    let rec loop (acc:'a list) (cnt:int) =
    match numer.MoveNext(), cnt < num-1 with
    | true, true -> loop (numer.Current::acc) (cnt+1)
    | _ -> acc
    match numer.MoveNext() with
    | true -> loop (numer.Current::[]) 0
    | false -> []



    let takeWhile pred (collection:#seq<'a>) =
    use numer = collection.GetEnumerator()
    let rec loop (acc:'a list) =
    match numer.MoveNext(), pred numer.Current with
    | true, true -> loop (numer.Current::acc)
    | _ -> acc
    match numer.MoveNext() with
    | true -> loop (numer.Current::[])
    | false -> []


    let skip num (collection:#seq<'a>) =
    use numer = collection.GetEnumerator()
    let rec takeRest (acc:'a list) =
    match numer.MoveNext() with
    | true -> takeRest (numer.Current::acc)
    | false -> acc
    let rec loop (acc:'a list) (cnt:int) =
    match numer.MoveNext(), cnt < num-1 with
    | true, true -> loop acc (cnt+1)
    | _ -> takeRest acc
    match numer.MoveNext() with
    | true -> loop [] 0
    | false -> []


    let skipWhile pred (collection:#seq<'a>) =
    use numer = collection.GetEnumerator()
    let rec takeRest (acc:'a list) =
    match numer.MoveNext() with
    | true -> takeRest (numer.Current::acc)
    | false -> acc
    let rec loop (acc:'a list) =
    match numer.MoveNext(), pred numer.Current with
    | true, true -> loop acc
    | _ -> takeRest (numer.Current::acc)
    match numer.MoveNext() with
    | true -> loop []
    | false -> []


    let indexFrom start (collection:#seq<'a>) =
    use numer = collection.GetEnumerator()
    let rec loop (acc:(int*'a)list) (cnt:int) v =
    match numer.MoveNext() with
    | true -> loop ((cnt,v)::acc) (cnt+1) (numer.Current)
    | false -> (cnt,v)::acc
    match numer.MoveNext() with
    | true -> loop [] start numer.Current
    | false -> []

    let index collection =
    indexFrom 0 collection


    let partitionAll num (collection:#seq<'a>)=
    use numer = collection.GetEnumerator()
    let rec addUntil cnt (acc:'a list list) (input:'a) =
    match numer.MoveNext() with
    | false ->
    match acc with
    | [] -> [input]::[]
    | ahd::atl ->
    match cnt < num with
    | true -> (input::ahd)::atl
    | false -> [input]::(ahd::atl)
    | true when cnt < num ->
    match acc with
    | [] -> addUntil (cnt+1) ([input]::[]) numer.Current
    | ahd::atl -> addUntil (cnt+1) ((input::ahd)::atl) numer.Current
    | true ->
    match acc with
    | [] -> []
    | ls -> addUntil 1 ([input]::ls) numer.Current
    match numer.MoveNext() with
    | true -> addUntil 0 [] numer.Current
    | false -> []


    let partition pred (collection:#seq<'a>) =
    let sift (accTrue,accFalse) input =
    match pred input with
    | true -> input::accTrue,accFalse
    | false -> accTrue,input::accFalse
    foldl sift ([],[]) collection


    let private unique (exists:HashSet<_>) hashfn acc input =
    match exists.Add (hashfn input) with
    | true -> input::acc
    | false -> acc

    let distinct (collection:#seq<'a>) =
    let exists = HashSet<int>()
    let unique' acc input = unique exists hash acc input
    foldl unique' [] collection


    let distinctBy (proj:'a->'key) (collection:#seq<'a>) =
    let exists = HashSet<'key>()
    let unique' acc input = unique exists proj acc input
    foldl unique' [] collection


    let distinctFrom (exists:HashSet<int>) (collection:#seq<'a>) =
    let unique' acc input = unique exists hash acc input
    foldl unique' [] collection


    // end of module Left

    let map ( f :'a->'b ) ( collection:#seq<'a> ) =
    Left.map f collection |> List.rev


    let filter (pred:'a -> bool) (collection:#seq<'a>) =
    Left.filter pred collection |> List.rev


    let collect ( f :'a->'b list ) ( collection:#seq<'a> ) =
    Left.collect f collection |> List.rev


    let take num (collection:#seq<'a>) =
    Left.take num collection |> List.rev


    let takeWhile pred (collection:#seq<'a>) =
    Left.takeWhile pred collection |> List.rev


    let skip num (collection:#seq<'a>) =
    Left.skip num collection |> List.rev


    let skipWhile pred (collection:#seq<'a>) =
    Left.skipWhile pred collection |> List.rev


    let index (collection:#seq<'a>) =
    Left.index collection |> List.rev

    let indexFrom start (collection:#seq<'a>) =
    Left.indexFrom start collection |> List.rev

    let partition pred (collection:#seq<'a>) =
    let accTrue,accFalse = Left.partition pred collection
    accTrue |> List.rev, accFalse |> List.rev


    let partitionAll num (collection:#seq<'a>)=
    use numer = collection.GetEnumerator()
    let rec addUntil cnt (acc:'a list list) (input:'a) =
    match numer.MoveNext() with
    | false ->
    match acc with
    | [] -> [input]::[]
    | hd::tl ->
    match cnt < num with
    | true -> (input::hd|>List.rev)::tl
    | false -> [input]::((hd|>List.rev)::tl)
    | true when cnt < num ->
    match acc with
    | [] -> addUntil (cnt+1) ([input]::[]) numer.Current
    | hd::tl -> addUntil (cnt+1) ((input::hd)::tl) numer.Current
    | true ->
    match acc with
    | [] -> []
    | hd::tl -> addUntil 1 ([input]::((hd|>List.rev)::tl)) numer.Current
    match numer.MoveNext() with
    | true -> addUntil 0 [] numer.Current
    | false -> []
    |> List.rev


    let distinct (collection:#seq<'a>) =
    Left.distinct collection |> List.rev


    let distinctBy (proj:'a->'key) (collection:#seq<'a>) =
    Left.distinctBy proj collection |> List.rev


    let distinctFrom (exists:HashSet<int>) (collection:#seq<'a>) =
    Left.distinctFrom exists collection |> List.rev


    let inline private findWith func acc input =
    match acc with
    | Some x -> Some (func x input)
    | None -> Some input


    let inline private optLoop func (collection:#seq<'a>) =
    use numer = collection.GetEnumerator()
    let rec loop acc input =
    match numer.MoveNext() with
    | true -> loop (func acc input) (numer.Current)
    | false -> func acc input
    match numer.MoveNext() with
    | true -> loop None numer.Current
    | false -> None


    let minOption (collection:#seq<'a>) =
    optLoop (findWith min) collection


    let maxOption (collection:#seq<'a>) =
    optLoop (findWith max) collection


    let inline sumOption (collection:#seq< ^T> when ^T : (static member (+) : ^T * ^T -> ^T)) =
    optLoop (findWith (+)) collection


    let inline avgOption (collection:#seq<'T> when ^T : (static member (+) : ^T * ^T -> ^T)) : float option =
    if Option.isNone (sumOption collection) then None else
    float (sumOption collection).Value / float (Seq.length collection) |> Some
    374 changes: 374 additions & 0 deletions 02_transducers.fs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,374 @@

    open System
    open Microsoft.FSharp.Collections
    open Microsoft.FSharp.Core.Printf
    open System.Collections.Generic
    open System.Collections.Concurrent
    open Fusion




    [<AutoOpen>]
    module Core =


    type Transducer<'a,'b> =
    /// partial application is the key to the functionality of a transducer
    /// transform should take a step function as its argument without and acc
    /// or input and then used by a fold or an unfold
    abstract transform<'r> : stepfn: ('r->'b->'r) -> acc:'r -> input:'a -> 'r


    // TODO Add another member to transducers that transforms the postfn on
    // a foldpost
    // OR another abstract type STateful transducer, that implements transducer


    /// When transducers are composed using this function t1
    /// will execute before t2
    let inline compose (t1:Transducer<'a,'b>) (t2:Transducer<'b,'c>) =
    { new Transducer<'a,'c> with
    member __.transform stepfn acc input =
    ( t2.transform >> t1.transform ) stepfn acc input
    }

    /// Comp should be used if transducers are being composed in a
    /// pipeline with `|>` The transducers will execute from top to
    /// bottom
    let inline comp (t1:Transducer<_,_>) (t2:Transducer<_,_>) =
    compose t2 t1


    /// Forward composition operator
    /// When transducers are composed using this operator the left transducer
    /// will execute first
    let inline (|>>) xf1 xf2 = compose xf1 xf2

    /// When transducers are composed using this operator the right transducer
    /// will execute first
    let inline (<<|) xf1 xf2 = comp xf1 xf2


    type FoldArgs<'a,'b> =
    abstract StepFn : ('b->'a->'b)
    abstract Acc : 'b

    let inline (|&>) (xf:Transducer<_,_>)(fld:FoldArgs<_,_>) =
    { new FoldArgs<_,_> with
    member __.StepFn = xf.transform fld.StepFn
    member __.Acc = []
    }

    let inline (<&|) (fld:FoldArgs<_,_>)(xf:Transducer<_,_>) =
    { new FoldArgs<_,_> with
    member __.StepFn = xf.transform fld.StepFn
    member __.Acc = []
    }

    let inline consfn xs x = x::xs

    let foldList =
    { new FoldArgs<_,_> with
    member __.StepFn = consfn
    member __.Acc = []
    }


    type UnfoldArgs<'a,'b,'c,'d> =
    abstract StepFn : ('c->'d->'c)
    abstract Acc : 'c
    abstract Pred : ('a->bool)
    abstract MapElm : ('a->'b)
    abstract Inc : ('a->'a)


    let inline (|~>) (xf:Transducer<_,_>)(uf:UnfoldArgs<_,_,_,_>) =
    { new UnfoldArgs<_,_,_,_> with
    member __.StepFn = xf.transform uf.StepFn
    member __.Acc = []
    member __.Pred = uf.Pred
    member __.MapElm = uf.MapElm
    member __.Inc = uf.Inc
    }

    let inline (<~|) (uf:UnfoldArgs<_,_,_,_>)(xf:Transducer<_,_>) =
    { new UnfoldArgs<_,_,_,_> with
    member __.StepFn = xf.transform uf.StepFn
    member __.Acc = []
    member __.Pred = uf.Pred
    member __.MapElm = uf.MapElm
    member __.Inc = uf.Inc
    }



    /// Concatting should always precede a reduction
    // concat IS a transducer as opposed to a function that returns a transducer
    let inline concat() =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    Folds.foldl stepfn acc input
    }


    let inline collect (func:'a -> #seq<'c>) =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    Folds.foldl stepfn acc (func input)
    }


    let inline map (func:'a->'b) =
    { new Transducer<_,_> with
    member __.transform (stepfn:'c->'b->'c) (acc:'c) (input:'a) =
    stepfn acc ( func input )
    }


    let inline filter pred =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    match pred input with
    | true -> stepfn acc input
    | false -> acc
    }




    let filterMap (pred:'a -> bool) mapfn =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    match pred input with
    | true -> stepfn acc (mapfn input)
    | false -> acc
    }


    let filterMapAlt pred funcTrue funcFalse =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    match pred input with
    | true -> stepfn acc ( funcTrue input )
    | false -> stepfn acc ( funcFalse input )
    }


    let mapWhen2 pred1 pred2 mapfn1 mapfn2 =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    match pred1 input, pred2 input with
    | true, _ -> stepfn acc ( mapfn1 input )
    | _ ,true -> stepfn acc ( mapfn2 input )
    | _ , _ -> acc
    }


    let choose() =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    match Option.isSome input with
    | true -> stepfn acc input.Value
    | false -> acc
    }

    /// take throws an invalid argument exception on negative input values
    let take num =
    let count = ref 0
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    match num with
    | x when x < 0 ->
    invalidArg "num" (sprintf "args for take must be postive, value passed in was %d" num )
    | 0 -> acc
    | _ ->
    match !count < num with
    | true -> incr count
    stepfn acc input
    | false -> acc
    }


    /// negative input value is the same as "take 0"
    let takeSafe num =
    let count = ref 0
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    match num with
    | x when x <= 0 -> acc
    | _ ->
    match !count < num with
    | true -> incr count
    stepfn acc input
    | false -> acc
    }




    let takeWhile (pred:'a -> bool) =
    let taking = ref true
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    taking := pred input
    match !taking with
    | true -> stepfn acc input
    | false -> acc }


    let skip num =
    let count = ref 0
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    match num with
    | x when x < 0 ->
    invalidArg "num" (sprintf "args for skip must be postive, value passed in was %d" num )
    | 0 -> stepfn acc input
    | _ ->
    match !count >= num with
    | true -> stepfn acc input
    | false -> incr count
    acc }


    let skipSafe num =
    let count = ref 0
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    match num with
    | x when x <= 0 -> stepfn acc input
    | _ ->
    match !count >= num with
    | true -> stepfn acc input
    | false -> incr count
    acc }


    let skipWhile (pred:'a -> bool) =
    let skipping = ref true
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    skipping := pred input
    match !skipping with
    | true -> acc
    | false -> stepfn acc input }


    let inline slice start finish =
    let start' = start-1
    let takeNum = if finish < start' then 0 else finish - start'
    let sc = ref 0 // skip count
    let tc = ref 0 // take count
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    match !sc < start' with
    | true -> incr sc; acc
    | false ->
    match !tc < takeNum with
    | true -> incr tc; stepfn acc input
    | false -> acc }


    let index() =
    let counter = ref 0
    let inc (cnt:int ref) input =
    let idx = !cnt
    incr cnt
    idx,input
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc (inc counter input) }


    /// Stateful version of index that can execute across a transduction
    let indexFrom (start:int) =
    let counter = ref start
    let inc (cnt:int ref) input =
    let idx = !cnt
    incr cnt
    idx,input
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc (inc counter input) }


    /// Stateful version of distinct that can operate across a reduction
    /// Should only be used inside of a function that returns a transducer
    // distinctS needs to return a transducer due to the value restriction
    let inline distinct() =
    let exists = HashSet<int>()
    let dedupe (input:'a) =
    exists.Add (hash input)
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    match dedupe input with
    | true -> stepfn acc input
    | false -> acc }


    /// Should only be used inside of a function that returns a transducer
    let distinctBy (proj:'a -> 'key) =
    let exists = HashSet<'key>()
    let dedupe (input:'a) =
    exists.Add (proj input)
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    match dedupe input with
    | true -> stepfn acc input
    | false -> acc }


    /// Should only be used inside of a function that returns a transducer
    let distinctFrom (other:HashSet<int>) =
    let exists = HashSet(other)
    let dedupe (input:'a) =
    exists.Add (hash input)
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    match dedupe input with
    | true -> stepfn acc input
    | false -> acc }


    // TODO - Implement the metamorphism version of Quicksort


    /// Create an empty hashset for storing hashes for distinction comparison
    let idSet() = HashSet<int>()


    let inline logf (msg) =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc (printf msg input; input) }


    let inline logfn (msg) =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc (printfn msg input; input) }



    // Ninja Logging Operators

    let inline ( !?! ) t1 =
    (logf ("\n| %A |")) |>> t1 |>> ( logf( "==> %A " ))

    let inline ( |?> ) t1 t2 =
    t1 |>> ( t2 |>> ( logf( "==> %A " )))

    let inline ( <?| ) t2 t1 =
    (logf (" %A =")) <<| t2 <<| (logf ("=> %A ")) <<| t1


    [<AutoOpen>]
    module CoreExtensions =
    type Transducer<'b,'c> with

    member self.Fold stepfn acc =
    Folds.foldl (self.transform stepfn) acc

    member self.Unfold stepfn (acc:'c) pred mapElm inc : 'a -> 'c =
    Folds.unfold (self.transform stepfn) acc pred mapElm inc
    286 changes: 286 additions & 0 deletions 03_collection_transducers.fs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,286 @@
    open System.Collections.Generic

    [<RequireQualifiedAccess>]
    module XCol =


    let map mapfn =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.map mapfn input )
    }

    let filter pred =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.filter pred input )
    }

    let collect (proj:'a -> 'b list) =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    Folds.foldl stepfn acc ( Folds.map proj input )
    }

    /// take the first 'num' elements from a sequence inside a transduction
    let take num =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.take num input )
    }


    let takeWhile pred =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.takeWhile pred input )
    }


    let skip num =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.skip num input )
    }


    let skipWhile pred =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.skipWhile pred input )
    }


    let index() =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.index input )
    }


    let indexFrom start =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.indexFrom start input )
    }


    let partition pred =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.partition pred input )
    }


    let partitionAll num =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.partitionAll num input )
    }


    let distinct() =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.distinct input )
    }

    let distinctBy proj =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.distinctBy proj input )
    }


    let distinctFrom (exists:HashSet<int>) =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.distinctFrom exists input )
    }


    let minOption() =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.minOption input )
    }


    let maxOption() =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.maxOption input )
    }


    let avgOption() =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.avgOption input )
    }



    let sumOption() =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.sumOption input )
    }


    let head() =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Seq.head input)
    }


    let last() =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Seq.last input)
    }


    let reduce redux =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Seq.reduce redux input)
    }


    let windowed size =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Seq.windowed size input)
    }


    let scan folder state =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Seq.scan folder state input)
    }



    let slice start finish =
    let start' = start-1
    let takeNum = if finish < start' then 0 else finish - start'
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc
    ( Folds.skip start' input
    |> Folds.take takeNum )
    }




    let compareWith comparer =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( let s1,s2 = input
    Seq.compareWith comparer s1 s2 )
    }


    let contains pred =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Seq.exists pred input)
    }


    let groupBy projection =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Seq.groupBy projection input)
    }


    let iterOver func =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Seq.iter func input; input )
    }

    [<RequireQualifiedAccess>]
    module Left =

    /// take the first 'num' elements from a sequence inside a transduction
    let take num =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.Left.take num input )
    }


    let takeWhile pred =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.Left.takeWhile pred input )
    }


    let skip num =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.Left.skip num input )
    }


    let skipWhile pred =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.Left.skipWhile pred input )
    }


    let index() =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.Left.indexFrom 0 input )
    }


    let indexFrom start =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.Left.indexFrom start input)
    }


    let partition pred =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.Left.partition pred input )
    }


    let partitionAll num =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.Left.partitionAll num input )
    }


    let distinct() =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.Left.distinct input )
    }


    let distinctBy proj =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.Left.distinctBy proj input )
    }


    let distinctFrom (exists:HashSet<int>) =
    { new Transducer<_,_> with
    member __.transform stepfn acc input =
    stepfn acc ( Folds.Left.distinctFrom exists input )
    }
    164 changes: 164 additions & 0 deletions 04_into.fs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,164 @@
    open System.Collections
    open System.Collections.Generic
    open System.Collections.Concurrent


    [<AutoOpen>]
    module Collections =

    // Pour the transducer into a particular form
    let inline private consfn xs x = x::xs

    let inline intoList2 (tdx:Transducer<'a,'b>) (collection:#seq<'a>) =
    consfn |> tdx.transform |> Folds.foldl |> fun fld -> fld [] collection

    //Folds.foldl (tdx.transform consReduc) [] collection |> List.rev


    let inline intoList (tdx:Transducer<'a,'b>) (collection:#seq<'a>) =
    Folds.foldl (tdx.transform consfn) [] collection |> List.rev


    let inline intoArray (tdx:Transducer<_,_>) (collection:#seq<_>) =
    collection |> intoList tdx |> Array.ofList


    let inline intoSeq (tdx:Transducer<_,_>) (collection:#seq<_>) =
    collection |> intoList tdx :> seq<_>

    type GenericList<'a> = System.Collections.Generic.List<'a>

    let inline intoGenericList (tdx:Transducer<_,_>) (collection:#seq<_>) =
    GenericList<_>( intoList tdx collection )


    let inline intoLinkedList (tdx:Transducer<_,_>) (collection:#seq<_>) =
    LinkedList( intoList tdx collection )


    let inline intoMap (tdx:Transducer<_,_>) (collection:#seq<_>) =
    let addelem (map:Map<_,_>) input = map.Add input
    Folds.foldl (tdx.transform addelem) (Map<_,_>([])) collection


    let inline intoSet (tdx:Transducer<_,_>) (collection:#seq<_>) =
    let addelem (set:Set<_>) input = set.Add input
    Folds.foldl (tdx.transform addelem) (Set<_>([])) collection


    let inline intoHashSet (tdx:Transducer<_,_>) (collection:#seq<_>) =
    let addelem (hs:HashSet<_>) input = hs.Add input |> ignore; hs
    Folds.foldl (tdx.transform addelem) (HashSet<_>()) collection


    type Dictionary<'K,'V> with
    member self.TryAdd(key,value) : bool =
    try self.Add(key,value); true
    with | _ -> false


    let inline intoDictionary (tdx:Transducer<_,_>) (collection:#seq<_>) =
    let addelem (dict:Dictionary<_,_>) input = dict.TryAdd input |> ignore; dict
    Folds.foldl (tdx.transform addelem) (Dictionary<_,_>()) collection


    let inline intoQueue (tdx:Transducer<_,_>) (collection:#seq<_>) =
    Queue<_>(intoList tdx collection)


    let inline intoStack (tdx:Transducer<_,_>) (collection:#seq<_>) =
    Stack<_>(intoList tdx collection)


    let inline intoConcurrentDictionary (tdx:Transducer<_,_>) (collection:#seq<_>) =
    let addelem (dict:ConcurrentDictionary<_,_>) input = dict.TryAdd input |> ignore; dict
    Folds.foldl (tdx.transform addelem) (ConcurrentDictionary<_,_>()) collection


    let inline intoConcurrentQueue (tdx:Transducer<_,_>) (collection:#seq<_>) =
    ConcurrentQueue<_>(intoList tdx collection)


    let inline intoConcurrentStack (tdx:Transducer<_,_>) (collection:#seq<_>) =
    ConcurrentStack<_>(intoList tdx collection)


    let inline intoConcurrentBag (tdx:Transducer<_,_>) (collection:#seq<_>) =
    ConcurrentBag<_>(intoList tdx collection)

    // need to change to transform.into (to:list, tdx:transducer, from:#seq<_> )

    type transduce =
    static member inline into (tdx:Transducer<_,_> , list: _ list ) = intoList tdx list
    static member inline into (tdx:Transducer<_,_> , list: _ [] ) = intoArray tdx list
    static member inline into (tdx:Transducer<_,_> , seqs:seq<_> ) = intoSeq tdx seqs
    static member inline into (tdx:Transducer<_,_> , list:GenericList<_> ) = intoGenericList tdx list
    static member inline into (tdx:Transducer<_,_> , list:LinkedList<_> ) = intoLinkedList tdx list
    static member inline into (tdx:Transducer<_,_> , hashset:HashSet<_> ) = intoHashSet tdx hashset
    static member inline into (tdx:Transducer<_,_> , map:Map<_,_> ) = intoMap tdx map
    static member inline into (tdx:Transducer<_,_> , set:Set<_> ) = intoSet tdx set
    static member inline into (tdx:Transducer<_,_> , dict:Dictionary<_,_> ) = intoDictionary tdx dict
    static member inline into (tdx:Transducer<_,_> , queue:Queue<_> ) = intoQueue tdx queue
    static member inline into (tdx:Transducer<_,_> , stack:Stack<_> ) = intoStack tdx stack
    static member inline into (tdx:Transducer<_,_> , dict:ConcurrentDictionary<_,_>) = intoConcurrentDictionary tdx dict
    static member inline into (tdx:Transducer<_,_> , queue:ConcurrentQueue<_> ) = intoConcurrentQueue tdx queue
    static member inline into (tdx:Transducer<_,_> , stack:ConcurrentStack<_> ) = intoConcurrentStack tdx stack
    static member inline into (tdx:Transducer<_,_> , bag:ConcurrentBag<_> ) = intoConcurrentBag tdx bag




    [<RequireQualifiedAccess>]
    module Left =

    // Pour the transducer into a particular form
    let inline private consReduc xs x = x::xs

    let inline intoList (tdx:Transducer<_,_>) (collection:#seq<_>) =
    Folds.foldl (tdx.transform consReduc) [] collection


    let inline intoArray (tdx:Transducer<_,_>) (collection:#seq<_>) =
    collection |> intoList tdx |> Array.ofList


    let inline intoSeq (tdx:Transducer<_,_>) (collection:#seq<_>) =
    collection |> intoList tdx :> seq<_>


    let inline intoGenericList (tdx:Transducer<_,_>) (collection:#seq<_>) =
    System.Collections.Generic.List<_>( intoList tdx collection )


    let inline intoLinkedList (tdx:Transducer<_,_>) (collection:#seq<_>) =
    LinkedList( intoList tdx collection )


    let inline intoQueue (tdx:Transducer<_,_>) (collection:#seq<_>) =
    Queue<_>(intoList tdx collection)


    let inline intoStack (tdx:Transducer<_,_>) (collection:#seq<_>) =
    Stack<_>(intoList tdx collection)


    let inline intoConcurrentQueue (tdx:Transducer<_,_>) (collection:#seq<_>) =
    ConcurrentQueue<_>(intoList tdx collection)


    let inline intoConcurrentStack (tdx:Transducer<_,_>) (collection:#seq<_>) =
    ConcurrentStack<_>(intoList tdx collection)


    // need to change to transform.into (to:list, tdx:transducer, from:#seq<_> )

    type transduce =
    static member inline into (tdx:Transducer<_,_> , list: _ list ) = intoList tdx list
    static member inline into (tdx:Transducer<_,_> , list: _ [] ) = intoArray tdx list
    static member inline into (tdx:Transducer<_,_> , seqs:seq<_> ) = intoSeq tdx seqs
    static member inline into (tdx:Transducer<_,_> , list:GenericList<_> ) = intoGenericList tdx list
    static member inline into (tdx:Transducer<_,_> , list:LinkedList<_> ) = intoLinkedList tdx list
    static member inline into (tdx:Transducer<_,_> , queue:Queue<_> ) = intoQueue tdx queue
    static member inline into (tdx:Transducer<_,_> , stack:Stack<_> ) = intoStack tdx stack
    static member inline into (tdx:Transducer<_,_> , queue:ConcurrentQueue<_> ) = intoConcurrentQueue tdx queue
    static member inline into (tdx:Transducer<_,_> , stack:ConcurrentStack<_> ) = intoConcurrentStack tdx stack
    214 changes: 214 additions & 0 deletions 05_exensions.fs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,214 @@
    open System
    open System.Collections
    open System.Collections.Generic
    open System.Collections.Concurrent
    open Microsoft.FSharp.Collections
    open Microsoft.FSharp.Control
    open System.Runtime.CompilerServices

    [<RequireQualifiedAccess>]
    module Seq =

    let inline transduce (tdz:Transducer<_,_>) (collection:#seq<_>) =
    intoSeq tdz collection

    let inline transduceL (tdz:Transducer<_,_>) (collection:#seq<_>) =
    Left.intoSeq tdz collection


    module Extensions =



    type List<'a> with

    /// Execute a trasduction across a list from the end to the start
    static member inline TransduceL (tdz:Transducer<_,_>) (ls:'a list) =
    Left.intoList tdz ls

    /// Execute a trasduction across this list from the end to the start
    member inline self.transduceL (tdz:Transducer<_,_>) =
    Left.intoList tdz self

    /// Execute a trasduction across this list from the start to the end
    member inline self.transduce (tdz:Transducer<_,_>) =
    intoList tdz self

    /// Execute a trasduction across a list from the end to the start
    static member inline Transduce (tdz:Transducer<_,_>) (ls:'a list) =
    intoList tdz ls




    type IEnumerable<'a> with

    member inline self.transduceL (tdz:Transducer<_,_>) =
    Left.intoList tdz self :> seq<_>

    /// Execute a trasduction across this list from the start to the end
    member inline self.transduce (tdz:Transducer<_,_>) =
    intoList tdz self :> seq<_>


    type System.Collections.Generic.List<'T> with

    static member inline TransduceL (tdz:Transducer<_,_>)
    (ls:System.Collections.Generic.List<'T>) =
    Left.intoGenericList tdz ls

    member inline self.transduceL (tdz:Transducer<_,_>) =
    Left.intoGenericList tdz self


    /// Execute a trasduction across this list from the start to the end
    member inline self.transduce (tdz:Transducer<_,_>) =
    intoGenericList tdz self

    /// Execute a trasduction across a list from the end to the start
    static member inline Transduce (tdz:Transducer<_,_>)
    (ls:System.Collections.Generic.List<_>) =
    intoGenericList tdz ls


    type LinkedList<'T> with
    static member inline Transduce (tdz:Transducer<_,_>) (linkls:LinkedList<'T>) =
    intoLinkedList tdz linkls

    static member inline TransduceL (tdz:Transducer<_,_>) (linkls:LinkedList<'T>) =
    Left.intoLinkedList tdz linkls

    member inline self.transduce (tdz:Transducer<_,_>) =
    intoLinkedList tdz self

    member inline self.transduceL (tdz:Transducer<_,_>) =
    Left.intoLinkedList tdz self


    type ``[]``<'a> with

    /// Execute a trasduction across an array from the end to the start
    static member inline TransduceL (tdz:Transducer<_,_>) (arr:'a []) =
    Left.intoArray tdz arr

    /// Execute a trasduction across this array from the end to the start
    member inline self.transduceL (tdz:Transducer<_,_>) =
    Left.intoArray tdz self

    /// Execute a trasduction across this array from the start to the end
    member inline self.transduce (tdz:Transducer<_,_>) =
    intoArray tdz self

    /// Execute a trasduction across an array from the start to the end
    static member inline Transduce (tdz:Transducer<_,_>) (arr:'a []) =
    intoArray tdz arr


    type HashSet<'a> with

    member inline self.transduce (tdz:Transducer<_,_>) =
    intoHashSet tdz self

    static member inline Transduce (tdz:Transducer<_,_>) (hashset:HashSet<_>) =
    intoHashSet tdz hashset


    type Dictionary<'K,'V> with

    static member inline Transduce (tdz:Transducer<_,_>) (dict:Dictionary<_,_>) =
    intoDictionary tdz dict

    member inline self.transduce (tdz:Transducer<_,_>) =
    intoDictionary tdz self


    type Map<'Key, 'Value when 'Key : comparison> with

    static member inline Transduce (tdz:Transducer<_,_>) (map:Map<_,_>) =
    intoMap tdz map

    member inline self.transduce (tdz:Transducer<_,_>) =
    intoMap tdz self


    type Set<'a when 'a : comparison> with

    member inline self.transduce (tdz:Transducer<_,_>) =
    intoSet tdz self

    static member inline Transduce (tdz:Transducer<_,_>) (set:Set<_>) =
    intoSet tdz set


    type Queue<'T> with
    static member inline Transduce (tdz:Transducer<_,_>) (queue:Queue<'T>) =
    intoQueue tdz queue

    static member inline TransduceL (tdz:Transducer<_,_>) (queue:Queue<'T>) =
    Left.intoQueue tdz queue

    member inline self.transduce (tdz:Transducer<_,_>) =
    intoQueue tdz self

    member inline self.transduceL (tdz:Transducer<_,_>) =
    Left.intoQueue tdz self


    type Stack<'T> with
    static member inline Transduce (tdz:Transducer<_,_>) (stack:Stack<'T>) =
    intoStack tdz stack

    static member inline TransduceL (tdz:Transducer<_,_>) (stack:Stack<'T>) =
    Left.intoStack tdz stack

    member inline self.transduce (tdz:Transducer<_,_>) =
    intoStack tdz self

    member inline self.transduceL (tdz:Transducer<_,_>) =
    Left.intoStack tdz self


    type ConcurrentDictionary<'K,'V> with

    static member inline Transduce (tdz:Transducer<_,_>) (dict:ConcurrentDictionary<_,_>) =
    intoConcurrentDictionary tdz dict

    member inline self.transduce (tdz:Transducer<_,_>) =
    intoConcurrentDictionary tdz self


    type ConcurrentBag<'T> with

    static member inline Transduce (tdz:Transducer<_,_>) (bag:ConcurrentBag<_>) =
    intoConcurrentBag tdz bag

    member inline self.transduce (tdz:Transducer<_,_>) =
    intoConcurrentBag tdz self


    type ConcurrentQueue<'T> with
    static member inline Transduce (tdz:Transducer<_,_>) (queue:ConcurrentQueue<'T>) =
    intoConcurrentQueue tdz queue

    static member inline TransduceL (tdz:Transducer<_,_>) (queue:ConcurrentQueue<'T>) =
    Left.intoConcurrentQueue tdz queue

    member inline self.transduce (tdz:Transducer<_,_>) =
    intoConcurrentQueue tdz self

    member inline self.transduceL (tdz:Transducer<_,_>) =
    Left.intoConcurrentQueue tdz self


    type ConcurrentStack<'T> with
    static member inline Transduce (tdz:Transducer<_,_>) (stack:ConcurrentStack<'T>) =
    intoConcurrentStack tdz stack

    static member inline TransduceL (tdz:Transducer<_,_>) (stack:ConcurrentStack<'T>) =
    Left.intoConcurrentStack tdz stack

    member inline self.transduce (tdz:Transducer<_,_>) =
    intoConcurrentStack tdz self

    member inline self.transduceL (tdz:Transducer<_,_>) =
    Left.intoConcurrentStack tdz self