Skip to content
Functional Experiment in Go
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.github Removed iterators and implemented channels (WIP) Feb 2, 2019
doc Added employee example code image Mar 10, 2019
.gitignore Added FloatStream, README + tests updates Feb 10, 2019
.golangci.yml Added golangci config Mar 10, 2019
LICENSE Initial commit Nov 5, 2018
Makefile Linting, README Mar 9, 2019
README.md Update README.md May 2, 2019
collector.go Tests + bug fix in CStream.ForEach Mar 9, 2019
collector_test.go Added employee example Mar 10, 2019
consumer.go Added Collector Feb 18, 2019
cstream.go Added CStream.Filter + updated README Mar 9, 2019
cstream_test.go Added CStream.Filter + updated README Mar 9, 2019
doc.go Stream.GroupBy, Maybe, generalisation of the use of Entry (#4) Nov 24, 2018
entry.go Comment format updated Feb 25, 2019
entry_test.go Test refinements for EntriesEqual Feb 22, 2019
entrybool.go Added EntryMap, EntrySlice, Map.GroupBy, removed internal use of hamt… Feb 3, 2019
entrybool_test.go Stream.GroupBy, Maybe, generalisation of the use of Entry (#4) Nov 24, 2018
entrybyte.go Added EntryByte Feb 23, 2019
entrybyte_test.go Added EntryByte Feb 23, 2019
entryfloat.go Added FloatStream, README + tests updates Feb 10, 2019
entryfloat_test.go Added NonMatch and AllMatch Feb 12, 2019
entryint.go (WIP) Added IntStream, Stream.MapToInt, EntryInt Feb 6, 2019
entryint_test.go (WIP) Added IntStream, Stream.MapToInt, EntryInt Feb 6, 2019
entrymap.go Enhanced Collectors, added EntryMap.Len, EntrySlice.Len, improved tes… Feb 21, 2019
entrymap_test.go Enhanced Collectors, added EntryMap.Len, EntrySlice.Len, improved tes… Feb 21, 2019
entryslice.go Documentation + FlattenEntrySliceToEntry Feb 21, 2019
entryslice_test.go Added Stream.Distinct Feb 21, 2019
entrystring.go Added EntryString.MapToEntryBytes Feb 23, 2019
entrystring_test.go Added EntryString.MapToEntryBytes Feb 23, 2019
example_function_test.go Added Stream: FlatMap, ToSlice Feb 21, 2019
example_maybe_test.go Added Stream: FlatMap, ToSlice Feb 21, 2019
example_predicate_test.go Added Predicate.Negate as an alias to Predicate.Not Feb 11, 2019
example_stream_test.go Documentation + FlattenEntrySliceToEntry Feb 21, 2019
floatstream.go Updated documentation Feb 27, 2019
floatstream_test.go Added FloatStream, README + tests updates Feb 10, 2019
function.go Updated documentation Feb 27, 2019
function_test.go Documentation + FlattenEntrySliceToEntry Feb 21, 2019
goconvey.sh Added NonMatch and AllMatch Feb 12, 2019
golangci-lint.sh Linting, README Mar 9, 2019
gomutesting.blacklist Improved EndsWith + tests Feb 24, 2019
gomutesting.sh Improved EndsWith + tests Feb 24, 2019
helpers_test.go Added Stream: FlatMap, ToSlice Feb 21, 2019
intstream.go Updated documentation Feb 27, 2019
intstream_test.go Added FloatStream, README + tests updates Feb 10, 2019
maybe.go Added TODO to Maybe Feb 23, 2019
maybe_test.go Added Maybe.Filter Feb 23, 2019
predicate.go Added to Stream: DropUntil, Take, TakeUntil, TakeWhile Feb 17, 2019
predicate_test.go Added Predicate.Xor Feb 17, 2019
producer.go Intermediary commit Feb 20, 2019
stream.go Documentation improvements Mar 9, 2019
stream_c.go Updated documentation Feb 27, 2019
stream_c_test.go Added Stream.ForEachC Feb 24, 2019
stream_test.go Minor refactoring for nil channel panics Feb 24, 2019
tuple0.go Enhanced Collectors, added EntryMap.Len, EntrySlice.Len, improved tes… Feb 21, 2019
tuple0_test.go Removed Tuple interface. Entry satisfies the requirement. Mar 11, 2019
tuple1.go Added Tuple*.MapMulti Mar 12, 2019
tuple1_test.go Added Tuple*.MapMulti Mar 12, 2019
tuple2.go Added Tuple*.MapMulti Mar 12, 2019
tuple2_test.go Added Tuple*.MapMulti Mar 12, 2019
tuple3.go Added Tuple*.MapMulti Mar 12, 2019
tuple3_test.go Added Tuple*.MapMulti Mar 12, 2019

README.md

ƒuego logo

ƒuego - Functional Experiment in Go

Tweet

fuego goreportcard cover.run

Buy Me A Coffee

ƒuego example

ƒuego example

Table of content

Overview

Making Go come to functional programming.

This is a research project in functional programming which I hope will prove useful!

ƒuego brings a few functional paradigms to Go. The intent is to save development time while promoting code readability and reduce the risk of complex bugs.

I hope you will find it useful!

Have fun!!

(toc)

Documentation

The code documentation and some examples can be found on godoc.

The tests form the best source of documentation. ƒuego comes with a good collection of unit tests and testable Go examples. Don't be shy, open them up and read them and tinker with them!

Note:
Most tests use unbuffered channels to help detect deadlocks. In real life scenarios, it is recommended to use buffered channels for increased performance.

(toc)

Installation

Download

go get github.com/seborama/fuego

Or for a specific version:

go get gopkg.in/seborama/fuego.v7

Import in your code

You can import the package in the usua Go fashiom.

To simplify usage, you can use an alias:

package sample

import ƒ "gopkg.in/seborama/fuego.v7"

...or import as an unqualified dot import:

package sample

import . "gopkg.in/seborama/fuego.v7"

(toc)

Example Stream

    strs := EntrySlice{
        EntryString("a"),
        EntryString("bb"),
        EntryString("cc"),
        EntryString("ddd"),
    }
    
    NewStreamFromSlice(strs, 500).
        Filter(isEntryString).
        Distinct().
        Collect(
            GroupingBy(
                stringLength,
                Mapping(
                    stringToUpper,
                    Filtering(
                        stringLengthGreaterThan(1),
                        ToEntrySlice()))))
    }

    // result: map[1:[] 2:[BB CC] 3:[DDD]]

(toc)

Contributions

Contributions and feedback are welcome.

For contributions, you must develop in TDD fashion and ideally provide Go testable examples (if meaningful).

If you have an idea to improve ƒuego, please share it via an issue. And if you like ƒuego give it a star to show your support for the project - it will put a smile on my face! 😊

Thanks!!

(toc)

The Golden rules of the game

  1. Producers close their channel. In other words, when you create a channel, you are responsible for closing it. Similarly, whenever ƒuego creates a channel, it is responsible for closing it.

  2. Consumers do not close channels.

  3. Producers and consumers should be running in separate Go routines to prevent deadlocks when the channels' buffers fill up.

(toc)

Pressure

Go channels support buffering that affects the behaviour when combining channels in a pipeline.

When the buffer of a Stream's channel of a consumer is full, the producer will not be able to send more data through to it. This protects downstream operations from overloading.

Presently, a Go channel cannot dynamically change its buffer size. This prevents from adapting the stream flexibly. Constructs that use 'select' on channels on the producer side can offer opportunities for mitigation.

(toc)

Concept: Entry

Entry is inspired by hamt.Entry. This is an elegant solution from Yota Toyama: the type can be anything so long as it respects the simple behaviour of theEntry interface. This provides an abstraction of types yet with known behaviour:

  • Hash(): identifies an Entry Uniquely.
  • Equal(): defines equality for a concrete type of Entry. Equal() is expected to be based on Hash() for non-basic types. Equal should ensure the compared Entry is of the same type as the reference Entry. For instance, EntryBool(false) and EntryInt(0) both have a Hash of 0, yet they aren't equal.

Several Entry implementations are provided:

  • EntryBool
  • EntryInt
  • EntryFloat
  • EntryString
  • EntryMap
  • EntrySlice
  • Tuples

Check the godoc for additional methods each of these may provide.

(toc)

Features summary

Streams:

  • Stream
  • IntStream
  • FloatStream
  • CStream - concurrent implementation of Stream

Functional Types:

  • Maybe
  • Tuple
  • Predicate:
    • True
    • False
    • FunctionPredicate

Functions:

  • Consumer
  • Function:
    • ToIntFunction
    • ToFloatFunction
  • BiFunction
  • StreamFunction:
    • FlattenEntrySliceToEntry
  • Predicate:
    • Or
    • Xor
    • And
    • Not / Negate

Collectors:

  • GroupingBy
  • Mapping
  • FlatMapping
  • Filtering
  • Reducing
  • ToEntrySlice

Check the godoc for full details.

(toc)

Concurrency

Concurrent streams are challenging to implement owing to ordering issues in parallel processing. At the moment, the view is that the most sensible approach is to delegate control to users. Multiple ƒuego streams can be created and data distributed across as desired. This empowers users of ƒuego to implement the desired behaviour of their pipelines.

Stream has some methods that fan out (e.g. ForEachC). See the godoc for further information and limitations.

I recommend Rob Pike's slides on Go concurrency patterns:

As a proof of concept and for facilitation, ƒuego has a CStream implementation to manage concurrently a collection of Streams.

(toc)

Collectors

A Collector is a mutable reduction operation, optionally transforming the accumulated result.

Collectors can be combined to express complex operations in a concise manner.
Simply put, a collector allows creating custom actions on a Stream.

ƒuego exposes a number of functional methods such as MapToInt, Head, LastN, Filter, etc...
Collectors also provide a few functional methods.

But... what if you need something else? And it is not straighforward or readable when combining the existing methods ƒuego offers?

Enters Collector: implement you own requirement functionally!
Focus on what needs doing in your streams (and delegate the details of the how to the implementation of your Collector).

(toc)

Known limitations

  • several operations may be memory intensive or poorly performing.

(toc)

Buy Me A Coffee

You can’t perform that action at this time.