functional programming in go

function programming experimental lib

why another fp lib

I like fp style and I haven’t found a lib with these features:

  • streamingly, I can handle infinite data source such as go channel or a socket reader
  • lazy evaluation, well, huge list processing wouldn’t make me oom
  • generic, the interface{} type ocurrs in a map function sucks
  • chain calls, functions should be compositional
  • clean, I hope the core of the lib would be clean
  • performance, good performance would be a bonus

And when I decide to build a new fp lib, the theory of lisp come to my mind immediately.

If I can bring cons,car,cdr into golang, that would be cool and attractive for me.

So I spend couple of days make this, and I hope you like it. Any feedback is welcome.

Own to the poor performance of golang's closure and small objects gc, the lisp like version
runs a little slow. So I have to refact the whole project with iterator pattern, for now it runs
2xtimes than before and faster than go-linq at least, enjoy it.

goos: darwin
goarch: amd64
pkg: demo/fpdemo
cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
BenchmarkFP-12             274879              3711 ns/op            1184 B/op         42 allocs/op
BenchmarkGoLinq-12         246768              4545 ns/op            1632 B/op         69 allocs/op

source

Stream is created from a source, source is a slice, a channel, or even a reader.

e.g. create stream from slice

StreamOf([]int{1, 2, 3})
StreamOf([]string{"a", "b", "c"})

e.g. create stream from channel

ch := make(chan string, 1)
StreamOf(ch)

e.g. create stream from iterator function

var i int
fn := func() (int, bool) {
	i++
	return i, i < 5
}
StreamOf(fn)

e.g. create stream from custom source

type Source interface {
	// source element type
	ElemType() reflect.Type
	// Next element
	Next() (reflect.Value, bool)
}

StreamOfSource(mySource)
// create a file source, read text line by line
file, _ := os.Open("example.txt")
defer file.Close()
source := NewLineSource(file)
StreamOfSource(source)

high order functions

Map

slice := []string{"a", "b", "c"}
var out []string
StreamOf(slice).Map(strings.ToUpper).ToSlice(&out)
suite.ElementsMatch(out, []string{"A", "B", "C"})

FlatMap

// flatmap optional boolean values
slice := []string{"a", "b", "c"}
var out []string
StreamOf(slice).FlatMap(func(e string) (string, bool) {
	return strings.ToUpper(e), e == "b"
}).ToSlice(&out)
suite.ElementsMatch(out, []string{"B"})

// flatmap optional error values
slice := []string{"a", "b", "c"}
out = StreamOf(slice).FlatMap(func(e string) (string, error) {
	if e == "b" {
		return strings.ToUpper(e), errors.New("error")
	}
	return strings.ToUpper(e), nil
}).Strings()
suite.ElementsMatch(out, []string{"A", "C"})

// flatmap sub collection
slice := []string{"abc", "de", "f"}
out := StreamOf(slice).FlatMap(func(s string) []byte {
	return []byte(s)
}).Bytes()
suite.Equal("abcdef", string(out))

Filter

slice := []string{"a", "b", "c"}
out := StreamOf(slice).Filter(func(s string) bool {
	return s == "b"
}).Strings()
suite.Equal([]string{"b"}, out)

Reject

slice := []string{"a", "b", "c"}
out := StreamOf(slice).Reject(func(s string) bool {
	return s == "b"
}).Strings()
suite.Equal([]string{"a", "c"}, out)

Foreach

var out string
slice := []string{"abc", "de", "f"}
out1 := StreamOf(slice).Foreach(func(s string) {
	out += s
}).Strings()
suite.Equal("abcdef", out)
suite.ElementsMatch(slice, out1)

Flatten

slice := []string{"abc", "de", "f"}
out := StreamOf(slice).Map(func(s string) []byte {
	return []byte(s)
}).Flatten().Bytes()
suite.Equal("abcdef", string(out))

deep flatten

slice := [][]string{
	{"abc", "de", "f"},
	{"g", "hi"},
}
out := StreamOf(slice).Map(func(s []string) [][]byte {
	return StreamOf(s).Map(func(st string) []byte {
		return []byte(st)
	}).Result().([][]byte)
}).Flatten().Flatten().Bytes()
suite.Equal("abcdefghi", string(out))

Partition/PartitionBy

source := []string{"a", "b", "c", "d"}

out := StreamOf(source).Partition(3).StringsList()
suite.Equal([][]string{
	{"a", "b", "c"},
	{"d"},
}, out)

slice := []string{"a", "b", "c", "d", "e", "c", "c"}
out := StreamOf(slice).PartitionBy(func(s string) bool {
	return s == "c"
}, true).StringsList()
suite.Equal([][]string{
	{"a", "b", "c"},
	{"d", "e", "c"},
	{"c"},
}, out)

Reduce/Reduce0

j { return i } return j } min := func(i, j int) int { if i < j { return i } return j } sum := func(i, j int) int { return i + j } source := []int{1, 2, 3, 4, 5, 6, 7} ret := StreamOf(source).Reduce0(max).Int() suite.Equal(int(7), ret) ret = StreamOf(source).Reduce0(min).Int() suite.Equal(int(1), ret) ret = StreamOf(source).Reduce0(sum).Int() suite.Equal(int(28), ret) ">
source := []string{"a", "b", "c", "d", "a", "c"}

out := StreamOf(source).Reduce(map[string]int{}, func(memo map[string]int, s string) map[string]int {
	memo[s] += 1
	return memo
}).Result().(map[string]int)
suite.Equal(map[string]int{
	"a": 2,
	"b": 1,
	"c": 2,
	"d": 1,
}, out)

max := func(i, j int) int {
	if i > j {
		return i
	}
	return j
}
min := func(i, j int) int {
	if i < j {
		return i
	}
	return j
}
sum := func(i, j int) int { return i + j }

source := []int{1, 2, 3, 4, 5, 6, 7}
ret := StreamOf(source).Reduce0(max).Int()
suite.Equal(int(7), ret)

ret = StreamOf(source).Reduce0(min).Int()
suite.Equal(int(1), ret)

ret = StreamOf(source).Reduce0(sum).Int()
suite.Equal(int(28), ret)

First

slice := []string{"abc", "de", "f"}
q := StreamOf(slice)
out := q.First()
suite.Equal("abc", out.String())

IsEmpty

slice := []string{"abc", "de", "f"}
q := StreamOf(slice)
suite.False(q.IsEmpty())
out := q.First()
suite.Equal("abc", out.String())

Take/TakeWhile

slice := []string{"abc", "de", "f"}
out := strings.Join(StreamOf(slice).Take(2).Strings(), "")
suite.Equal("abcde", out)

slice := []string{"a", "b", "c"}
out := StreamOf(slice).TakeWhile(func(v string) bool {
	return v < "c"
}).Strings()
suite.Equal([]string{"a", "b"}, out)

Skip/SkipWhile

slice := []string{"abc", "de", "f"}
out := strings.Join(StreamOf(slice).Skip(2).Strings(), "")
suite.Equal("f", out)

slice := []string{"a", "b", "c"}
out := StreamOf(slice).SkipWhile(func(v string) bool {
	return v < "c"
}).Strings()
suite.Equal([]string{"c"}, out)

Sort/SortBy

slice := []int{1, 3, 2}
out := StreamOf(slice).Sort().Ints()
suite.Equal([]int{1, 2, 3}, out)

slice := []string{"abc", "de", "f"}
out := StreamOf(slice).SortBy(func(a, b string) bool {
	return len(a) < len(b)
}).Strings()
suite.Equal([]string{"f", "de", "abc"}, out)

Uniq/UniqBy

slice := []int{1, 3, 2, 1, 2, 1, 3}
out := StreamOf(slice).Uniq().Ints()
suite.ElementsMatch([]int{1, 2, 3}, out)

slice := []int{1, 3, 2, 1, 2, 1, 3}
out := StreamOf(slice).UniqBy(func(i int) bool {
	return i%2 == 0
}).Ints()
suite.ElementsMatch([]int{1, 2}, out)

Size

out := StreamOf(slice).Size()
suite.Equal(2, out)

Contains/ContainsBy

slice := []string{"abc", "de", "f"}
q := StreamOf(slice)
suite.True(q.Contains("de"))

slice := []string{"abc", "de", "f"}
q := StreamOf(slice)
suite.True(q.ContainsBy(func(s string) bool { return strings.ToUpper(s) == "F" }))

GroupBy

slice1 := []string{"abc", "de", "f", "gh"}
q := StreamOf(slice1).Map(strings.ToUpper).GroupBy(func(s string) int {
	return len(s)
}).Result().(map[int][]string)
suite.Equal(map[int][]string{
	1: {"F"},
	2: {"DE", "GH"},
	3: {"ABC"},
}, q)

Append/Prepend

slice := []string{"abc", "de"}
out := StreamOf(slice).Append("A").Strings()
suite.Equal([]string{"abc", "de", "A"}, out)

slice := []string{"abc", "de"}
out := StreamOf(slice).Prepend("A").Strings()
suite.Equal([]string{"A", "abc", "de"}, out)

Union/Sub/Interact

slice1 := []string{"abc", "de", "f"}
slice2 := []string{"g", "hi"}
q1 := StreamOf(slice1).Map(strings.ToUpper)
q2 := StreamOf(slice2).Map(strings.ToUpper)
out := q2.Union(q1).Strings()
suite.Equal([]string{"ABC", "DE", "F", "G", "HI"}, out)

slice1 := []int{1, 2, 3, 4}
slice2 := []int{2, 1}
out := StreamOf(slice1).Sub(StreamOf(slice2)).Ints()
suite.Equal([]int{3, 4}, out)

slice1 := []int{1, 2, 3, 4}
slice2 := []int{2, 1}
out := StreamOf(slice1).Interact(StreamOf(slice2)).Ints()
suite.ElementsMatch([]int{1, 2}, out)

Zip

slice1 := []int{1, 2, 3}
slice2 := []int{4, 5, 6, 7}
out := StreamOf(slice1).Zip(StreamOf(slice2), func(i, j int) string {
	return strconv.FormatInt(int64(i+j), 10)
}).Strings()
suite.ElementsMatch([]string{"5", "7", "9"}, out)

Result

stream transform would not work unless Run/ToSlice/Result is invoked.

Run

use Run if you just want stream flows but do not care about the result

// the numbers would not print without Run
StreamOf(source).Foreach(func(i int) {
	fmt.Println(i)
}).Run()

ToSlice

slice := []string{"a", "b", "c"}
var out []string
StreamOf(slice).Map(strings.ToUpper).ToSlice(&out)
suite.ElementsMatch(out, []string{"A", "B", "C"})

Result

slice := []string{"a", "b", "c"}
q := StreamOf(slice).Map(strings.ToUpper)
out := q.Result().([]string)
suite.ElementsMatch(out, []string{"A", "B", "C"})
Owner
Jason
what you've done defines you
Jason
Similar Resources

I will be uploading some basic programming in Golang so if you want to contribute please Fork this repo and contriute.

I will be uploading some basic programming in Golang so if you want to contribute please Fork this repo and contriute.

Go-language I will be uploading some basic programming in Golang so if you want to contribute please Fork this repo and contriute. This repo is for pr

Jan 21, 2022

Web programming tutorial with Golang

Tutorial de programação Web com Golang Para rodar o servidor Entre na pasta web_app, onde está o main.go cd caminho/para/pasta/web_app Agora execute

Jan 19, 2022

Repository for COMP 429 Programming Assignment# 1 - A simple chat application, by Sabra Bilodeau.

Chatty COMP 429 Programming Assignment 1 A Chat Application for Remote Message Exchange by Sabra Bilodeau Getting Started with Chatty Building the Pro

Nov 28, 2021

Solving structy.net data structures & algorithms programming problems in Go (with Tests)

structy.net Solving structy.net data structures & algorithms programming problems in Go (with Tests) I. Introduction 000. hey programmer 001. max-valu

Oct 18, 2022

A programming job interview question problem

Unscramble a scrambled URL Problem statement The problem statement follows. I copied it literally because there's no good way to summarize and retain

Nov 9, 2021

A repository for showcasing my knowledge of the Google Go (2009) programming language, and continuing to learn the language.

Learning Google Golang (programming language) Not to be confused with the Go! programming language by Francis McCabe I don't know very much about the

Nov 6, 2022

A repository for showcasing my knowledge of the Go! (2003) programming language, and continuing to learn the language.

A repository for showcasing my knowledge of the Go! (2003) programming language, and continuing to learn the language.

Learning Go! (programming language) Not to be confused with Google Golang (2009) I don't know too much about the Go! programming language, but I know

Oct 22, 2022

Repo Tugas Basic Programming Part 2(Input/Output, Branching, Looping) ALTA Immersive BE5

Cara mengerjakan tugas hari ke 2 clone project ini dengan cara git clone https://github.com/jackthepanda96/Intro-to-Algoritm-Part2.git setelah clone

Dec 15, 2021

Repo Tugas Basic Programming Part 4(Complexity Analysis, Array, Slice, Function) ALTA Immersive BE5

Cara mengerjakan tugas hari ke 4 clone project ini dengan cara git clone https://github.com/ALTA-Immersive-BE5/Basic-Programming-Part4.git setelah cl

Dec 15, 2021
Related tags
An experimental generic functional utility library inspired by Lodash

go-godash An experimental generic functional utility library inspired by Lodash Implemented functions Map Reduce Sum Filter Take TakeWhile Drop DropWh

May 31, 2022
Go programming language secure coding practices guide

You can download this book in the following formats: PDF, Mobi and ePub. Introduction Go Language - Web Application Secure Coding Practices is a guide

Jan 9, 2023
The Little Go Book is a free introduction to Google's Go programming language
The Little Go Book is a free introduction to Google's Go programming language

The Little Go Book is a free introduction to Google's Go programming language. It's aimed at developers who might not be quite comfortable with the idea of pointers and static typing. It's longer than the other Little books, but hopefully still captures that little feeling.

Jan 2, 2023
Some examples for the programming language Go.

Golang_Examples Bubblesort: simple implementation of bubble sort algorithm in Go Level: Beginner GenericStack: a stack (LIFO collection) that can hold

Jul 28, 2022
Crash Course about the programming language Go / Golang.
Crash Course about the programming language Go / Golang.

Crash Course about the programming language Go / Golang. In this course I have covered some important concepts and topics in programming.

Oct 10, 2022
A complete guide to undersatnd golang programming language, web requests, JSON and creating web APIs with mongodb

Golang series A complete guide to undersatnd golang programming language, web requests, JSON and creating web APIs with mongodb LearnCodeonline.in 01

Jan 1, 2023
go programming language tutorial

go programming language tutorial Hello World Hello World fmt package Variables Short Declaration The Var Keyword Exploring Type Own Type Conversion Ty

Aug 27, 2022
An open source programming language that makes it easy to build simple
An open source programming language that makes it easy to build simple

The Go Programming Language Go is an open source programming language that makes it easy to build simple, reliable, and efficient software. Gopher ima

Oct 15, 2021
Programming Paradigm With Golang
Programming Paradigm With Golang

Programming-Paradigm After running python3 1_22.py you'll get a prompt: which, after entering start and the end of the interval, should create next wi

Oct 16, 2021
A practical journey into the Golang Programming Language

OneTutorial - A practical journey into the Golang Programming Language This little project will help you touch many topics around Golang, in a small a

Oct 21, 2021