Skip to content

zx80live/gofp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Functional programming in GO

Introduction

This library was inspired by Scala (collection API, functional paradigm and, concurrence API etc). It allows to program in Go using functional style similar to Scala. It enables us to combine the efficiency of FP and performance of Golang. There is an opportunity to work with mutable/immutable collections, futures which are monads.

Table of contents

Getting started

Before using functional library add dependency in your go.mod file:

require github.com/zx80live/gofp v1.0.1

and then import the following package in your project:

import . "github.com/zx80live/gofp/fp"

Or do the following steps if you want to create an empty project:

  1. Create new go-module project in your $WORK_DIR directory
# create your project dir
cd $WORK_DIR
mkdir test-gofp
cd test-gofp

# create your go-module
go mod init example.com/username/test-gofp
  1. Add dependency in your go.mod file:
echo 'require github.com/zx80live/gofp v1.0.1' >> go.mod
cat go.mod

The result of previous command should be:

module example.com/pav/test-gofp

go 1.15
require github.com/zx80live/gofp v1.0.1
  1. Create your first go-file in your preffered editor, for example:
vim test.go
  1. Write the following code in the $WORK_DIR/test-gofp/test.go file:
package main

import (
	"fmt"
    . "github.com/zx80live/gofp/fp"
)

func main() {
	fmt.Println("Hello functional programming in GO!")

  l := MkIntList(1,2,3,4,5,-6,-7,-8,9)
  res1 := l.Filter(EvenInt.And(PosInt)).
            MapInt(func(e int) int { return e * 10})

  fmt.Println(res1.ToString())
}
  1. Execute file:
go run test.go

The result of above command should be:

Hello functional programming in GO!
List(20,40)
  1. Explore this library by the examples which are presented in that documentation. Good luck!

Collection API

Current library supports the following collection types: Arrays, Lists and Options. Each type is monad and supports functions such as Map, FlatMap, Filter and etc.

[πŸ •]

List

All examples of this section use a IntList type. But this API is supported in the other array types also. (See Supported list types section) [πŸ •]

List structure

List is recursive functional data structure which has head and tail as sublist. For example, an IntList(1,2,3) will be presented in the following structure:

   1 ──▢ ( 2 ──▢ ( 3 ──▢ Nil ) )
  β””β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜          
   ↑               ↑
  head            tail

List is implemented in the following structure:

type IntList struct {
  head *int
  tail *IntList
}

[πŸ •]

Create list

// Create list
// O(n)
func MkIntList(elements ...int) IntList

// Construct list by prepend head
// O(1)
func (l IntList) Cons(e int) IntList

Example:

// create list by factory
var l IntList = MkIntList(1,2,3,4,5)

// create list from Nil
l2 := NilInt.Cons(5).Cons(4).Cons(3).Cons(2).Cons(1)  // equals IntList(1,2,3,4,5)

// create list from boxed (rich) types
l3 := Int(10).Cons(20).Cons(30)               // List(30,20,10)
l4 := String("one").Cons("two").Cons("three") // List("three", "two", "one")

[πŸ •]

List.Copy

// Copy references of elements to new list
// O(n)
func (l IntList) Copy() IntList

Example:

l1 := MkIntList(1,2,3,4,5)
l2 := l1.Copy()

[πŸ •]

List.Count

// Count elements which satisfy a predicate
// O(1..n)
func (l IntList) Count(predicate func(int) bool)

Example:

l := MkIntList(1,2,3,4,5)
l.Count(func(e int) bool { return e % 2 == 0})    // 2
l.Count(EvenInt)                                  // 2

[πŸ •]

List.Drops

// Returns new list without n-first elements
// O(1..n)
func (l IntList) Drop(n int) IntList

// Returns new list without n-last elements
// O(1..n)
func (l IntList) DropRight(n int) IntList

// Returns new list without first elements which statisfy a predicate
// O(1..n)
func (l IntList) DropWhile(predicate func(int) bool) IntList

Example:

l := MkIntList(10,20,30,40,50)
res1 := l.Drop(2)                                 // IntList(30,40,50)
res2 := l.DropRight(2)                            // IntList(10,20,30)
res3 := l.DropWhile(func (e int) bool { e < 40 }) // IntList(40,50)                      

[πŸ •]

List.Empty NonEmpty

// Returns true if list is empty
// O(n)
func (l IntList) IsEmpty() bool

// Returns true if list is not empty
// O(n)
func (l IntList) NonEmpty() bool

Example:

l1 := MkIntList(1,2,3)
res1 := l1.IsEmpty()      // false
res2 := l1.NoEmpty()      // true

l2 := MkIntList()    
res3 := l2.IsEmpty()      // true
res4 := l2.NonEmpty()     // fase

res5 := NilInt.IsEmpty()  // true
res6 := NilInt.NonEmpty() // false

[πŸ •]

List.Equals

// Returns true if both lists are equal
// O(n)
func (a IntLIst) Equals(b IntList) bool

Example:

// compare the simple lists
l1 := MkIntList(10,20,30,40,50)
l2 := MkIntList(10,20,30,40,50)
l3 := MkIntList({10,20,30)

l1.Equals(l2)   // true
l1.Equals(l3)   // false
                   
// compare the nested lists
l4 := MkIntListList(MkIntList(1,2), MkIntList(3,4,5))           
l5 := MkIntListList(MkIntList(1,2), MkIntList(3,4,5)) 
l6 := MkIntListList(MkIntList(1,2,3), MkIntList(4,5))           
                 
l4.Equals(l5)  // true
l4.Equals(l6)  // false

[πŸ •]

List.Filter

// Returns new list with elements which statisfy a predicate
// O(n)
func (l IntList) Filter(predicate func(int) bool) IntList

Example:

l := MkIntList(1,-2,-3,4,5,-6,7,8,-9,10)
res := l.
         Filter(func (e int) bool { return e % 2 == 0}).   // filter even numbers
         Filter(func (e int) bool { return e >= 0 })       // filter positive numbers

fmt.Println(res.ToString())    // IntList(4, 8, 10)

res2 := l.Filter(EvenInt).Filter(PosInt)                   // use library predicates O(n)
res3 := l.Filter(EvenInt.And(PosInt))                      // compose predicates     O(n)

[πŸ •]

List.Find

// Returns first element which statisfy a predicate
// O(1..n)
func (l IntList) Find(predicate func(int) bool)

Example:

l := IntList(1,2,3,4,5,6)

var res1 IntOption = l.Find(func(e int) bool { return e == 3 }) // Some(3)
var res2 IntOption = l.Find(EvenInt)                            // Some(2)
var res3 IntOption = l.Find(NegInt)                             // None

[πŸ •]

List.FlatMap

// FlatMap gives the ability to chain operations together
func (l IntList) FlatMap<Type>(f func(int) <Type>List) <Type>List

// examples
func (l IntList) FlatMapInt(f func(int) IntList) IntList
func (l IntList) FlatMapString(f func(int) StringList) StringList
...

Example:

// Example: flatten nested list
// List(List(1,2), Nil, List(3,4,5), List(6,7))
l := MkIntListList(MkIntList(1,2), NilInt, MkIntList(3,4,5), MkIntList(6,7)) 
l.FlatMapInt(func(e IntList) IntList { return e })        // List(1,2,3,4,5,6,7)
l.FlatMapInt(func(e IntList) IntList { 
    return e.MapInt(func(e int) int) { return e * 10 }})  // List(10,20,30,40,50,60,70)

[πŸ •]

List.Flatten

// Collapse the nested elements of a collection to flat collection
func (l <Type>ListList) Flatten() <Type>List
func (l <Type>OptionList) Flatten() <Type>List

// examples
func (l IntIntList) Flatten() IntList
func (l IntOptionList) Flatten() IntList

Example:

// List(List(1,2,3), Nil, List(4,5), List(6,7))
l := MkIntListList(MkIntList(1,2,3), Nil, MkIntList(4,5), MkIntList(6, 7))
var res IntList = l.Flatten()   // List(1,2,3,4,5,6,7)

[πŸ •]

List.FoldLeft

// Applies binary function to each element of list going left to right
// O(n)
// z - initial value
func (l IntList) FoldLeft<Type>(z <Type>, func(<Type>, int) <Type>) <Type>

// examples
func (l IntList) FoldLeftInt(z Int, func(int, int) int) int
func (l IntList) FoldLeftString(z string, func(string, int) string) string

Example:

l := MkIntList(1,2,3,4,5)


sum := l.FoldLeftInt(
          0, 
          func(acc, el) int { return acc + el})   // sum = (((((0 + 1) + 2) + 3) + 4) + 5)

str := l.FoldLeftString(
          ">", 
          func(acc, el) string { return fmt.Sprintf("%v|%v", acc, el)}) // >1|2|3|4|5

[πŸ •]

List.Foreach

// Iterate over elements
// O(n)
func (l IntList) Foreach(func(int))

Example:

l := MkIntList(1,2,3)
f.Foreach(func(e int) {
    fmt.Println("> ", e)
})

[πŸ •]

List.GroupBy

// Partitions this list into a map of according to some discriminator function
func (l <A>List) GroupBy<K>(func(<A>)<K>) map[<K>]<A>List

// examples
func (l IntList) GroupByInt(func(int) int) map[int]IntList
func (l AnyList) GroupByAny(func(Any)Any) map[Any]AnyList

Example: group by identity

l1 := MkIntList(1,2,1,1,3,2)
res1 := l1.GroupByInt(func(e int) int { return e }) /* Map(1 -> List(1,1,1)
                                                           2 -> List(2,2)
                                                           3 -> List(3))  */
res2 := l1.GroutByInt(IntIdentity)                  // the same as res1

Example: group by different attributes

type Shape struct {
  name  string
  color string
  area  int
}

shapes := NilAny.
  Cons(Shape{"circle", "green", 10}).
  Cons(Shape{"triangle", "yellow", 30}).
  Cons(Shape{"polygon", "green", 10}).
  Cons(Shape{"triangle", "green", 10}).
  Cons(Shape{"circle", "red", 20}).  
  Cons(Shape{"polygon", "red", 20}).
  Cons(Shape{"circle", "yellow", 30}).
  Cons(Shape{"triangle", "red", 20}).
  Cons(Shape{"polygon", "yellow", 30})

// Group shapes by name
byShape := func(e Any) Any { return e.(Shape).name }
res1 := shapes.GroupByAny(byShape)
/*
 Map(
   "polygon"  -> List({"polygon" "green" 10}, {"polygon" "red" 20}, {"polygon" "yellow" 30})
   "triangle" -> List({"triangle" "green" 10}, {"triangle" "red" 20}, {"triangle" "yellow" 30})
   "circle"   -> List({"circle" "green" 10}, {"circle" "red" 20}, {"circle" "yellow" 30})
 )
 */

// Group shapes by color
byColor := func(e Any) Any { return e.(Shape).color }
res2 := shapes.GroupByAny(byColor)
/*
 Map(
   "yellow" -> List({"circle" "yellow" 30}, {"triangle" "yellow" 30}, {"polygon" "yellow" 30})
   "red"    -> List({"circle" "red" 20}, {"triangle" "red" 20}, {"polygon" "red" 20})
   "green"  -> List({"circle" "green" 10}, {"triangle" "green" 10}, {"polygon" "green" 10})
 )
*/

byArea := func(e Any) Any { return e.(Shape).area }
res3 := shapes.GroupByAny(byArea)
/*
 Map (
   30 -> List({"circle" "yellow" 30}, {"triangle" "yellow" 30}, {"polygon" "yellow" 30})
   20 -> List({"circle" "red" 20}, {"triangle" "red" 20}, {"polygon" "red" 20})
   10 -> List({"circle" "green" 10}, {"triangle" "green" 10}, {"polygon" "green" 10})
 )
*/

[πŸ •]

List.Heads and tails

// Returns head of list or throws exeption if list is empty
// O(1)
func (l IntList) Head() int

// Returns optional head from list
// O(1)
func (l IntList) HeadOption() IntOption

// Returns tail as list without first element
// O(1)
func (l IntList) Tail() IntList

Example:

l := MkIntList(1,2,3)
h1 := l.Head()                      // 1
t1 := l.Tail()                      // List(2,3)
h1Opt := l.HeadOption()             // Some(1)
h2Opt := l.Tail().Tail().Tail()     // NoneInt
l.Tail().Tail().Tail().Head()       // panic("there is no heads")

[πŸ •]

List.Map

// Transform each element of list to other type
// O(n)
func (l IntList) Map<Type>(func (int) <Type>) <Type>List

// examples
func(l IntList) MapInt(func (int) int) IntList
func(l IntList) MapString(func (int) string) StringList

Example:

l := MkIntList(1,2,3)
r1 := l.MapInt(func(e int) int { return e * 10})                        // List(10,20,30)
r2 := l.MapString(func (e int) string { return fmt.Sprintf("<%v>", e)}) // List("<1>","<2>","<3>")

[πŸ •]

List.MkString

// Make string representation of that list with decorated elements and separator
// O(n)
func (l IntList) MkString(start, sep, end string) string

Example:

l := MkIntList(1,2,3)
str := l.MkString("<", "|", ">")      // "<1|2|3>"

[πŸ •]

List.Nil

// Empty list, can be used as initial tail before creating
var Nil<Type> <Type>List

// examples
var NilInt IntList = ...
var NilString StringList = ...
...

Example:

// create list from empty tail
l := NilInt.Cons(3).Cons(2).Cons(1)   // List(1,2,3)

[πŸ •]

List.Cons

// Create new list with new head and tail as current list
// O(1)
func (l IntList) Cons(e int) IntList

Example:

// create list from empty tail
l1 := NilInt.Cons(3).Cons(2).Cons(1)   // List(1,2,3)

l2 := MkIntList(1,2,3)
l3 := l2.Cons(4)                       // List(4,1,2,3)

[πŸ •]

List.Reduce

// Reduces elements of list using associative binary operator
// O(n)
func (l IntList) Reduce(func (int, int) int) int

Example:

l := MkIntList(1,2,3)
sum := l.Reduce(func(acc, el int) int { return acc + el })  // sum = 1 + 2 + 3

[πŸ •]

List.Reverse

// Reverse order of list elements
// O(n)
func (l IntList) Reverse() IntList

Example:

l1 := MkIntList(1,2,3)
l2 := l1.Reverse()                       // List(3,2,1)

[πŸ •]

List.Size

// Count elements of list
// O(n)
func (l IntList) Size() int

Example:

l1 := MkIntList(1,2,3)
l2 := MkIntList()

res1 := l1.Size()         // 3
res2 := l2.Size()         // 0
res3 := NilInt            // 0

[πŸ •]

List.Takes

// Returns first n-elements
// O(1..n)
func (l IntList) Take(n int) IntList

// Returns last n-elements
// O(1..n)
func (l IntList) TakeRight(n int) IntList

// Returns first elements which statisfy a predicate
// O(1..n)
func (l IntList) TakeWhile(func(int) bool) IntList

Example:

l := IntList(10,20,30,40,50)
res1 := l.Take(2)                                 // List(10,20)
res2 := l.TakeRight(2)                            // List(40,50)
res3 := l.TakeWhile(func (e int) bool { e < 40})  // List(10,20,30)

[πŸ •]

List.ToArray

// Returns elements of list as array
// O(n)
func (l IntList) ToArray() []int

Example:

l := MkIntList(1,2,3)
a := l.ToArray()          // []int{1,2,3}

[πŸ •]

List.ToString

// Transform list to string
func (l IntList) ToString() string

Example:

l1 := MkIntList(1,2,3)
res1 := l1.ToString()                                              // "List(1,2,3)"
l2 := MkIntListList(
        MkIntList(1,2), 
        NilInt, 
        MkIntList(3,4))  // "List(List(1,2), List(), List(3,4))"

[πŸ •]

List.Zip

// Returns a collection of combined corresponding elements in pairs
// Resulting list will have min-length of input collections
func (l IntList) ZipIntList(l2 IntList) Tuple2List
func (l IntList) ZipStringList(l2 StirngList) Tuple2List
...

Example:

l1 := MkIntList(1,2,3)
l2 := MkStringList("a", "b", "c")

res1 := l1.ZipStringList(l2)  
/* List(Tuple(1, "a"), 
        Tuple(2, "b"), 
        Tuple(3, "b")) */
                                   
res2 := l1.ZipStringList(MkStringList("a", "b"))
/* List(Tuple(1, "a"), 
        Tuple(2, "b")) */

res3 := l1.ZipStringList(MkStringList("a", "b", "c", "d", "e"))
/* List(Tuple(1, "a"), 
        Tuple(2, "b"), 
        Tuple(3, "b")) */

[πŸ •]

List.ZipAll

// Returns a collection of combined corresponding elements in pairs
// Resulting list will have max-length of input collections
// If one of corresponding element isn't found then default value will be used
func (l IntList) ZipAllIntList(l2 IntList, 
                               thisDefault Int, 
                               thatDefault Int) Tuple2List
func (l IntList) ZipAllStringList(l2 StringList, 
                                  thisDefault Int, 
                                  thatDefault string) Tuple2List
...

Example:

l1 := MkIntList(1,2,3)
l2 := MkStringList("a", "b", "c")
l1Default := -100
l2Default := "NONE"

res1 := l1.ZipAllStringList(l2, l1Default, l2Default)  
/* List(Tuple(1, "a"), 
        Tuple(2, "b"), 
        Tuple(3, "b")) */
                                   
res2 := l1.ZipAllStringList(MkStringList("a", "b"), 
                            l1Default, 
                            l2Default)
/* List(Tuple(1, "a"), 
        Tuple(2, "b"),
        Tuple(3, "NONE")) */

res3 := l1.ZipStringLitst(MkStringList("a", "b", "c", "d", "e"),
                          l1Default,
                          l2Default)
/* List(Tuple(1, "a"), 
        Tuple(2, "b"), 
        Tuple(3, "b"),
        Tuple(-100, "d"),
        Tuple(-100, "e")) */

[πŸ •]

List.ZipWithIndex

// Returns list of tuples which contains corresponding elements and its index
func (l IntList) ZipWithIndex() Tuple2List
...

Example:

l1 := MkIntList(1024, 2048, 4096)
res1 := l1.ZipWithIndex()
/* List(Tuple(1024, 0),
        Tuple(2048, 1),
        Tuple(4096, 2))*/
        
l2 := MkStringList("a", "b", "c")
res2 := l2.ZipWithIndex()
/* List(Tuple("a", 0),
        Tuple("b", 1),
        Tuple("c", 2))*/

[πŸ •]

Supported list types

Supported list types (click to expand)
Array type Scala analogue Go analogue
BoolList List[Boolean]
StringList List[String]
IntList List[Int]
Int64List List[Long]
ByteList List[Byte]
RuneList List[Char]
Float32List List[Float]
Float64List List[Double]
AnyList List[Any]
BoolArrayList List[Array[Bool]]
StringArrayList List[Array[String]]
IntArrayList List[Array[Int]]
Int64ArrayList List[Array[Long]]
ByteArrayList List[Array[Byte]]
RuneArrayList List[Array[Char]]
Float32ArrayList List[Array[Float]]
Float64ArrayList List[Array[Double]]
AnyArrayList List[Array[Any]]
BoolOptionList List[Option[Boolean]]
StringOptionList List[Option[String]]
IntOptionList List[Option[Int]]
Int64OptionList List[Option[Long]]
ByteOptionList List[Option[Byte]]
RuneOptionList List[Option[Char]]
Float32OptionList List[Option[Float]]
Float64OptionList List[Option[Double]]
AnyOptionList List[Option[Any]]
BoolListList List[List[Boolean]]
StringListList List[List[String]]
IntListList List[List[Int]]
Int64ListList List[List[Long]]
ByteListList List[List[Byte]]
RuneListList List[List[Char]]
Float32ListList List[List[Float]]
Float64ListList List[List[Double]]
AnyListList List[List[Any]]

[πŸ •]

Option

All examples of this section use a IntOption type. But this API is supported in the other array types also. (See Supported option types section)

Create option

func MkIntOption(e int) IntOption
func IntOpt(e int) IntOption

Example:

o1 := MkIntOption(10)     // Some(10)
o2 := IntOpt(20)            // Some(20)

[πŸ •]

Option.Equals

// Returns true if both options are equal
func (a IntOption) Equals(b IntOption) bool

Example:

o1 := IntOpt(10)
o2 := IntOpt(20)
o3 := IntOpt(10)

o1.Equals(o2)            // false
o1.Equals(o3)            // true
o1.Equals(NoneInt)       // false
NoneInt.Equals(NoneInt)  // true

[πŸ •]

Option.Filter

// Filter content of option by predicate
func (o IntOption) Filter(predicate func(int)bool) IntOption

Example:

o := IntOption(10)
res1 := o.Filter(func(e int) bool { return e % 2 == 0})  // Some(10)
res2 := o.Filter(EvenInt)                                // Some(10)
res3 := o.Filter(func(e int) bool { return e == 20 })    // None
res4 := o.Filter(NegInt)                                 // None

[πŸ •]

Option.FlatMap

// FlatMap gives the ability to chain operations together
func (o IntOption) FlatMap<Type>(f func(int) <Type>Option) <Type>Option

// examples
func (o IntOption) FlatMapInt(f func(int) IntOption) IntOption
func (o IntOption) FlatMapString(f func(int) StringOption) StringOption
...

Example:

// Task: calculate the sum of elements
//       if all elements are defined then the sum will be defined too
//       if one or more elements are not defined then the sum will not be defined too

// implementation of the task
sumFunc := func(a, b, c IntOption) IntOption {
    sum := a.FlatMapInt(func (av int) IntOption {
        return b.FlatMapInt(func bv int) IntOption {
            return c.MapInt(func cv int) IntOption {
                return av + bv + cv
            } 
        }
    })
    return sum
}

// Case when a, b, c are defined
a := IntOpt(10)
b := IntOpt(20)
c := IntOpt(30)

sumFunc(a, b, c)                                          // Some(60)


// Cases when one or more of a, b, c are not defined
sumFunc(IntOpt(10), NoneInt, IntOpt(30))                  // None
sumFunc(IntOpt(10), IntOpt(20), NoneInt)                  // None
sumFunc(NoneInt, IntOpt(20), IntOpt(30))                  // None
sumFunc(NoneInt, NoneInt, IntOpt(30))                     // None
...

[πŸ •]

Option.Flatten

// Collapse the nested option to flat option
func (o IntIntOption) IntOption

Example:

o := MkIntOptionOption(MkIntOption(10))    // Some(Some(10))
flatten := o.Flatten()                         // Some(10)

[πŸ •]

Option.FoldLeft

// Applies binary function to element of option
// z - initial value
func (l IntOption) FoldLeft<Type>(z <Type>, func(<Type>, int) <Type>) <Type>

// examples
func (l IntOption) FoldLeftInt(z Int, func(int, int) int) int
func (l IntOption) FoldLeftString(z string, func(string, int) string) string
...

Example:

o := IntOpt(10)
res1 := l.FoldLeftInt(
            0, 
            func(acc, el) int { return acc + el})   // sum = 0 + 10

[πŸ •]

Option.Foreach

// Iterate over content
func (l IntOption) Foreach(func(int))

Example:

l := IntOpt(10)
f.Foreach(func(e int) {
    fmt.Println("> ", e)
})

[πŸ •]

Option.IsDefined

// Returns true if option contains a value
func (o IntOption) IsDefined() bool

Example:

IntOption(10).IsDefined()     // true
NoneInt.IsDefined()           // false

[πŸ •]

Option.IsEmpty

// Returns true if option is not defined
func (o IntOption) IsEmpty() bool

Example:

NoneInt.IsEmpty()             // true
IntOpt(10).IsEmpty()          // false

[πŸ •]

Option.Map

// Transform element of option to other type
func (l IntOption) Map<Type>(func (int) <Type>) <Type>Option

// examples
func(l IntOption) MapInt(func (int) int) IntOption
func(l IntOption) MapString(func (int) string) StringOption

Example:

o := IntOpt(10)
res1 := o.MapInt(func (e int) int { return e * 10 })                       // Some(100)
res2 := o.MapString(func (e int) string { return fmt.Sprintf("<%v>", e) }) // Some("<10>") 

[πŸ •]

Option.None

There are empty option constants for each supported optional type

var NoneInt IntOption = ...
var NoneString IntOption = ...
...

Example:

o1 := NoneInt            // None
o2 := NoneString         // None

func parseIp(str string) StringOption {
    if str != "" { 
        return StringOpt(str) 
    } else {
        return NoneString
    } 
}

ip1 := parseIp("")           // None
ip2 := parseIp("127.0.0.1")  // Some("127.0.0.1")

[πŸ •]

Option.ToString

// Transform option to string
func (o IntOption) string

Example:

var o1 IntOption = IntOption(10)
var o2 IntOption = NoneInt

var str1 string = o1.ToString()      // "Some(10)"
var str2 string = o2.TOString()      // "None"

[πŸ •]

Supported option types

Supported option types (click to expand)
Option type Scala analogue
BoolOption Option[Boolean]
StringOption Option[String]
IntOption Option[Int]
Int64Option Option[Long]
ByteOption Option[Byte]
RuneOption Option[Char]
Float32Option Option[Float]
Float64Option Option[Double]
AnyOption Option[Any]
BoolOptionOption Option[Option[Boolean]]
StringOptionOption Option[Option[String]]
IntOptionOption Option[Option[Int]]
Int64OptionOption Option[Option[Long]]
ByteOptionOption Option[Option[Byte]]
RuneOptionOption Option[Option[Char]]
Float32OptionOption Option[Option[Float]]
AnyOptionOption Option[Option[Double]]
BoolArrayOption Option[Array[Boolean]]
StringArrayOption Option[Array[String]]
IntArrayOption Option[Array[Int]]
Int64ArrayOption Option[Array[Long]]
ByteArrayOption Option[Array[Byte]]
RuneArrayOption Option[Array[Char]]
Float32ArrayOption Option[Array[Float]]
Float64ArrayOption Option[Array[Double]]
AnyArrayOption Option[Array[Any]]
BoolListOption Option[List[Boolean]]
StringListOption Option[List[String]]
IntListOption Option[List[Int]]
Int64ListOption Option[List[Long]]
ByteListOption Option[List[Byte]]
RuneListOption Option[List[Char]]
Float32ListOption Option[List[Float]]
Float64ListOption Option[List[Double]]
AnyListOption Option[List[Any]]

[πŸ •]

Tuple2

Tuple2 is just a pair of two elements any types. Tuples are used in the Zip operations under collections, for example (see List.Zip, Array.Zip sections). [πŸ •]

Create tuple2

Example:

t1 := Tuple2 {10, "hello" }  // Tuple(10, "Hello")

// accessing to tuple's fields
var t1_e1 Any = t1.E1           // Any(10)
var t2_e2 Any = t2.E2           // Any("Hello")

t2 := Tuple2 {t1, MkIntList(1,2,3)} 
/* Tuple(Tuple(10, "hello"), List(1,2,3)) */

var t2_e1 Any = t2.E1   // Any(Tuple(10, "hello"))
var t2_e2 Any = t2.E2   // Any(List(1,2,3))

[πŸ •]

Tuple2.Equals

// Deep equality of two tuples
func (a Tuple2) Equals(b Tuple2) bool

Example:

t1 := Tuple2 {10, "hello" }
t2 := Tuple2 {10, "hello" }
t3 := Tuple2 {t1, MkIntList(1,2,3) }
t4 := Tuple2 {t1, MkIntList(1,2,3) }

t1.Equals(t2)                // true
t1.Equals(t3)                // false
t3.Equals(t4)                // true

[πŸ •]

Tuple2.ToString

// Transform tuple to string representation
func (t Tuple2) ToString String

Example:

t1 := Tuple2 {10, "hello"}
t1.ToString()       // "Tuple(10, hello)"

t2 := Tuple2 { t1, MkIntList(1,2,3) }
t2.ToString()       // "Tuple(Tuple(10, hello), List(1,2,3))" 

[πŸ •]

Array

Array is just wrapper for go-arrays which contains convenient functions. All examples of this section use a IntArray type. But this API is supported in the other array types also. (See Supported array types section) Warning, current implementation of the array wrapper is mutable data structure.

Create array

type IntArray []int

Example:

arr := IntArray([]int{10, 20, 30})

[πŸ •]

Array.Count

// Returns count of elements which satisfy a predicate
// O(n)
func (a IntArray) Count(predicate func(int) bool) int

Example:

arr := IntArray([]int{1,2,3,4,5})
arr.Count(func (e int) bool { return e % 2 == 0})         // 2
arr.Count(EvenInt)                                        // 2
arr.Count(PosInt)                                         // 5
arr.Count(NegInt)                                         // 0

[πŸ •]

Array.Drops

// Returns new array without n-first elements
// O(1..n)
func (a IntArray) Drop(n int) IntArray

// Returns new array without n-last elements
// O(1..n)
func (a IntArray) DropRight(n int) IntArray

// Returns new array without first elements which statisfy a predicate
// O(1..n)
func (a IntArray) DropWhile(predicate func(int) bool) IntArray

Example:

arr := IntArray([]int{10,20,30,40,50})
res1 := arr.Drop(2)                                 // Array(30,40,50)
res2 := arr.DropRight(2)                            // Array(10,20,30)
res3 := arr.DropWhile(func (e int) bool { e < 40 }) // Array(40,50)

[πŸ •]

Array.Equals

// Returns true if both arrays are equal
// O(n)
func (a IntArray) Equals(b IntArray) bool

Example:

arr1 := IntArray([]int{10,20,30,40,50})
arr2 := IntArray([]int{10,20,30,40,50})
arr3 := IntArray([]int{10,20,30})

arr1.Equals(arr2)   // true
arr1.Equals(arr3)   // false

[πŸ •]

Array.Filter

// Returns new array with elements which statisfy a predicate
// O(n)
func (a IntArray) Filter(predicate func(int) bool) IntArray

Example:

arr := IntArray([]int {1,-2,-3,4,5,-6,7,8,-9,10})
res := arr.
         Filter(func (e int) bool { return e % 2 == 0}).   // filter even numbers
         Filter(func (e int) bool { return e >= 0 })       // filter positive numbers

fmt.Println(res.ToString())    // [4, 8, 10]

res2 := arr.Filter(EvenInt).Filter(PosInt)                 // use library predicates
res3 := arr.Filter(EvenInt.And(PosInt))                    // compose predicates

[πŸ •]

Array.Find

// Returns first element which statisfy a predicate
// O(1..n)
func (a IntArray) Find(predicate func(int) bool) IntOption

Example:

arr := IntArray([]int {1,2,3,4,5,6})

var res1 IntOption = arr.Find(func(e int) bool { return e == 3 }) // Some(3)
var res2 IntOption = arr.Find(EvenInt)                            // Some(2)
var res3 IntOption = arr.Find(NegInt)                             // None

[πŸ •]

Array.Foreach

// Applies function `f` to each element of array. 
// O(n)
func (a IntArray) Foreach(f func(int))

Example:

arr := IntArray([]int{10, 20, 30})

// functional stype
arr.Foreach(func (e int) {              
    fmt.Println(e)           // print each element
})

// functional style (shortest)
arr.Foreach(PrintlnInt)

// imperative style
for _, e := range arr {
    fmt.Println(e)
}

[πŸ •]

Array.Heads and tails

// Returns head of array or throws exeption if array is empty
// O(1)
func (a IntArray) Head() int

// Returns optional head from array
// O(1)
func (a IntArray) HeadOption() IntOption

// Returns array without first element
// O(c)
func (a IntArray) Tail() IntArray

Example:

arr := IntArray([]int{10, 20, 30})

var h = arr.Head()                      // 10
var hopt IntOption = arr.HeadOption()   // Some(10)
var tail IntArray = arr.Tail()          // IntArray(20, 30)
var tail2 = tail.Tail()                 // IntArray(30)
var tail3 = tail2.Tail()                // empty array

var hopt3 = tail3.HeadOption()          // NoneInt
tail3.Head()                            // panic("there is no heads")

[πŸ •]

Array.Map

// Transform each element of array to new element
// O(n)
func (a IntArray) Map<Type>(transformer func(int) <Type>) <Type>Array

func (a IntArray) MapInt(transformer func(int) int) IntArray
func (a IntArray) MapString(transformer func(int) string) StringArray
...

Example:

arr := IntArray([]int{10, 20, 30})

var res StringArray = arr.
                        MapInt(func(e int) int { return e * 10 }).
                        MapString(func (e int) string) { return fmt.Sprintf("~%v~", e) }

res.Foreach(PrintString)
Output:
~100~
~200~
~300~

[πŸ •]

Array.MkString

// Make string representation of that array with decorated elements and separator
// O(n)
func (a IntArray) MkString(start, sep, end string) string

Example:

arr := IntArray([]int{1,2,3})
fmt.Println(arr.MkString("(", "|", ")"))  // (1|2|3)

[πŸ •]

Array.takes

// Returns first n-elements
// O(1..n)
func (a IntArray) Take(n int) IntArray

// Returns last n-elements
// O(1..n)
func (a IntArray) TakeRight(n int) IntArray

// Returns first elements which statisfy a predicate
// O(1..n)
func (a IntArray) TakeWhile(predicate func(int) bool) IntArray

Example:

arr := IntArray([]int{10,20,30,40,50})
res1 := arr.Take(2)                                 // Array(10,20)
res2 := arr.TakeRight(2)                            // Array(40,50)
res3 := arr.TakeWhile(func (e int) bool { e < 40})  // Array(10,20,30)

[πŸ •]

Array.ToList

// Transform array to recursive functional data structure
// O(n)
func (a IntArray) ToList() IntList

Example:

arr := IntArray([]int{1,2,3})
var l IntList = arr.ToList()

[πŸ •]

Array.ToString

// Make string representation of that array
// O(n)
func (a IntArray) ToString() string

Example:

arr := IntArray([]int{1,2,3})
fmt.Println(arr.ToString())                        // [1,2,3]

arr2 := IntIntArray([]int{1,2}, []int[]{3,4,5})
fmt.Println(arr2.ToString())                       // [[1,2], [3,4,5]]          

[πŸ •]

Array.Zip

// Returns an array of combined corresponding elements in pairs
// Resulting array will have min-length of input collections
func (a IntArray) ZipIntArray(a2 IntArray) Tuple2Array
func (a IntArray) ZipStrinArray(a2 StirngArray) Tuple2Array
...

Example:

a1 := IntArray([]int{1,2,3})
a2 := StringArray([]string{"a", "b", "c"})

res1 := a1.ZipStringArray(a2)  
/* Array(Tuple(1, "a"), 
         Tuple(2, "b"), 
         Tuple(3, "b")) */
                                   
res2 := a1.ZipStringArray(StringArray([]string{"a", "b"}))
/* Array(Tuple(1, "a"), 
         Tuple(2, "b")) */

res3 := a1.ZipStringArray(StringArray([]string{"a", "b", "c", "d", "e"}))
/* Array(Tuple(1, "a"), 
         Tuple(2, "b"), 
         Tuple(3, "b")) */

[πŸ •]

Array.ZipAll

// Returns an array of combined corresponding elements in pairs
// Resulting array will have max-length of input collections
// If one of corresponding element isn't found then default value will be used
func (a IntArray) ZipAllIntArray(a2 IntArray, 
                                 thisDefault Int, 
                                 thatDefault Int) Tuple2Array
func (a IntArray) ZipAllStringList(a2 StringArray, 
                                   thisDefault Int, 
                                   thatDefault string) Tuple2Array
...

Example:

a1 := IntArray([]int{1,2,3})
a2 := StringArray([]string{"a", "b", "c"})
l1Default := -100
l2Default := "NONE"

res1 := a1.ZipAllStringArray(a2, l1Default, l2Default)  
/* Array(Tuple(1, "a"), 
         Tuple(2, "b"), 
         Tuple(3, "b")) */
                                   
res2 := a1.ZipAllStringArray(StringArray([]string{"a", "b"}), 
                             l1Default, 
                             l2Default)
/* Array(Tuple(1, "a"), 
         Tuple(2, "b"),
         Tuple(3, "NONE")) */

res3 := a1.ZipStringArray(StringArray([]string{"a", "b", "c", "d", "e"}),
                          l1Default,
                          l2Default)
/* Array(Tuple(1, "a"), 
         Tuple(2, "b"), 
         Tuple(3, "b"),
         Tuple(-100, "d"),
         Tuple(-100, "e")) */

[πŸ •]

Array.ZipWithIndex

// Returns array of tuples which contains corresponding elements and its index
func (a IntArray) ZipWithIndex() Tuple2Array
...

Example:

a1 := IntArray([]int{1024, 2048, 4096})
res1 := a1.ZipWithIndex()
/* Array(Tuple(1024, 0),
         Tuple(2048, 1),
         Tuple(4096, 2))*/
        
a2 := StringArray([]string{"a", "b", "c"})
res2 := a2.ZipWithIndex()
/* Array(Tuple("a", 0),
         Tuple("b", 1),
         Tuple("c", 2))*/

[πŸ •]

Supported array types

Supported array types (click to expand)
Array type Scala analogue Go analogue
BoolArray Array[Bool] []bool
StringArray Array[String] []string
IntArray Array[Int] []int
Int64Array Array[Long] []int64
ByteArray Array[Byte] []byte
RuneArray Array[Rune] []rune
Float32Array Array[Float] []float32
Float64Array Array[Long] []float64
AnyArray Array[Any] []Any
BoolArrayArray Array[Array[Boolean]] [][]bool
StringArrayArray Array[Array[String]] [][]string
IntArrayArray Array[Array[Int]] [][]int
Int64ArrayArray Array[Array[Long]] [][]int64
ByteArrayArray Array[Array[Byte]] [][]byte
RuneArrayArray Array[Array[Char]] [][]rune
Float32ArrayArray Array[Array[Float]] [][]float32
Float64ArrayArray Array[Array[Double]] [][]float64
AnyArrayArray Array[Array[Any]] [][]Any

[πŸ •]

Boxed types

Boxed types are just wrappers under primitive go-types. These wrappers support additional operations which are desrcibed in this section.

[πŸ •]

Underlined

// Returns underlined value from boxed
func (e Int) Underlined() int
func (e String) Underlined() string
...

Example:

var a Int = Int(10)   // explicit boxing
var b Int = 20        // implicit boxing

var v1 int = a.Underlined()   // returns underlined value 10
var v2 int = b.Underlined()   // returns underlined value 20

[πŸ •]

Converters

String.ToArray

// Converts string to array of runes (character codes)
func (s String) ToArray() RuneArray

Example:

s := String("Hello")
arr := s.ToArray()      // RuneArray(72,101,108,108,111)

[πŸ •]

String.ToLetterArray

// Coverts string to letter array
func (s String) ToLetterArray() StringArray

Example:

s := String("Hello")
arr := s.ToLetterArray()  // StringArray("H", "e", "l", "l", "o")

[πŸ •]

String.ToInt

// Converts string to integer or throws exception for wrong format 
func (s String) ToInt Int

Example:

var n1 Int = String("10").ToInt()     // Int(10)
var n2 Int = String("zz").ToInt()     // panic("wrong format")

[πŸ •]

String.ToIntOption

// Converts string to Some(int) for correct format and None for wrong format
func (s String) ToIntOption() IntOption

Example:

var n1 IntOption = String("10").ToIntOption()  // Some(10)
var n2 IntOption = String("zz").ToIntOption()  // None

[πŸ •]

List constructors

// Create list from two elements `a` and `b`
func (a Int) Cons(b Int) IntList
func (a String) Cons(b String) StringList
...

Example:

l1 := Int(10).Cons(20)                         // List(20, 10)
l2 := String("one").Cons("two").Cons("three")  // List("three", "two", "one")

[πŸ •]

Range constructor

To

// Creates list with values from range from=n, to=t inclusive
func (n Int) To(t Int) IntList

Example:

l := Int(0).To(5)     // List(0,1,2,3,4,5)

[πŸ •]

Until

// Creates list with values from range from=n, to=(t-1)
func (n Int) Until(t Int) IntList

Example:

l := Int(0).To(5)     // List(0,1,2,3,4)

[πŸ •]

Math and logic operations

IsBetween

// check if a number is > left and < right (exclusive)
func (a Int) IsBetween(left, right int) bool

Example:

Int(10).IsBetween(9, 15)      // true
Int(10).IsBetween(0, 5)       // false
Int(10).IsBetween(10, 11)     // false

[πŸ •]

IsBetweenInclusive

// check if a number is >= left and <= right (inclusive)
func (a Int) IsBetweenInclusive(left, right int) bool

Example:

Int(10).IsBetween(10, 15)      // true
Int(10).IsBetween(0, 5)        // false

[πŸ •]

Min/Max numeric

// Returns min value of `a` and `b`
func (a Int) Min(b Int) Int
func (a Byte) Min(b Byte) Byte
...

// Returns max value of `a` and `b`
func (a Int) Max(b Int) Int
func (a Byte) Max(b Byte) Byte
...

Example:

res1 := Int(10).Min(20)     // 10
res2 := Int(10).Max(20)     // 20

[πŸ •]

Supported boxed types

Supported boxed types (click to expand)
Boxed type Go type
Bool bool
String string
Int int
Int8 int8
Int16 int16
Int32 int32
Int64 int64
Uint uint
Uint16 uint16
Uint32 uint32
Uint64 uint64
Uintptr uintptr
Byte byte
Rune rune
Float32 float32
Float64 float64
Complex64 complex64
Complex128 complex128
Any interface {}

[πŸ •]

Predicates

Predicates are used as function's arguments in the following operations on monads: Filter, Find, Count, Exist ... [πŸ •]

Empty predicates

// Always returns true for all input values
var EmptyIntPredicate IntPredicate = func(t int) bool { return true }
...

Example:

func getFilter() IntPredicate {
  var filterType string = config.getProperty("filter")
  
  if filterType == "even" {
     return EvenInt  // func (e int) bool { return e % 2 == 0 }
  } else if filterType == "odd" {
     return OddInt   // func (e int) bool { return e % 2 != 0 }
  } else {
    return EmptyIntPredicate   // default filter is no-filter
  }
}

l := MkIntList(1,2,3)

res1 := l.Filter(getFilter())  // if config propery does not contain
                               // filter type then filtering will not use

[πŸ •]

Numeric predicates

// Check if number is even
var EvenInt IntPredicate = ...
var EvenInt64 Int64Predicate = ...
var EvenByte BytePredicate = ...
var EvenRune RunePredicate = ...

// Check if number is odd
var OddInt IntPredicate = ...
...

// Check if number is negative
var NegInt IntPredicate = ...
...

// Check if number is positive
var PosInt IntPredicate = ...
...

// Check if number is zero
var ZeroInt IntPredicate = ...
...

// Check if number is equal to 1
var OneInt IntPredicate = ...
...

Examples:

l := MkIntList(1,2,-3,-4,5,6,-7,8,9,0)

res1 := l.Filter(EvenInt)                // List(2,-4,6,8,0)
res2 := l.Filter(NegInt)                 // List(-3,-4,-7)
res3 := l.Filter(EvenInt).Filter(NegInt) // List(-4)

[πŸ •]

String predicates

// Build string predicate which check if string is matched to regexp
func MatchRegexp(r *regexp.Regexp) StringPredicate

// Build string predicate which check if string is matched to pattern
func MatchRegexpString(pattern string) StringPredicate

Examples:

l := MkStringList("Hello", "abc", "127.0.0.1", "255.255.255.0", "world", "127", "255")

var matchIp StringPredicate = 
        MatchRegexpString("[\\d]{1,3}\\.[\\d]{1,3}\\.[\\d]{1,3}\\.[\\d]{1,3}")
   
ipList := l.Filter(matchIp)           // List("127.0.0.1", "255.255.255.0")

var onlyWords = MatchRegexpString("[a-zA-Z]+")
words := l.Filter(onlyWords)          // List("Hello", "abc", "world")

[πŸ •]

Predicates composition

// Apply boolean operator to two predicates
func (p1 IntPredicate) And(p2 IntPredicate) IntPredicate
func (p1 IntPredicate) Or(p2 IntPredicate) IntPredicate
func (p1 IntPredicate) Neg(p2 IntPredicate) IntPredicate
func (p1 IntPredicate) Xor(p2 IntPredicate) IntPredicate
...

Examples:

l := MkIntList(1,-2,3,4,5,-6,7,8,9,0)

var p1 IntPredicate = func(e int) bool { return e % 2 == 0 }  // even numbers
var p2 IntPredicate = func(e int) bool { return e < 0 }       // neg numbers

p3 := p1.And(p2)

l.Filter(p3)     // List(-2,-6)

[πŸ •]

Supported predicate types

Supported predicate types (click to expand)
Predicate type
BoolPredicate
StringPredicate
IntPredicate
Int64Predicate
BytePredicate
RunePredicate
Float32Predicate
Float64Predicate
AnyPredicate
BoolArrayPredicate
StringArrayPredicate
IntArrayPredicate
Int64ArrayPredicate
ByteArrayPredicate
RuneArrayPredicate
Float32ArrayPredicate
Float64ArrayPredicate
AnyArrayPredicate
BoolArrayArrayPredicate
StringArrayArrayPredicate
IntArrayArrayPredicate
Int64ArrayArrayPredicate
ByteArrayArrayPredicate
RuneArrayArrayPredicate
Float32ArrayArrayPredicate
Float64ArrayArrayPredicate
AnyArrayArrayPredicate
BoolOptionPredicate
StringOptionPredicate
IntOptionPredicate
Int64OptionPredicate
ByteOptionPredicate
RuneOptionPredicate
Float64OptionPredicate
AnyOptionPredicate
BoolOptionOptionPredicate
StringOptionOptionPredicate
IntOptionOptionPredicate
Int64OptionOptionPredicate
RuneOptionOptionPredicate
Float32OptionOptionPredicate
Float64OptionOptionPredicate
AnyOptionOptionPredicate
BoolArrayOptionPredicate
StringArrayOptionPredicate
IntArrayOptionPredicate
Int64ArrayOptionPredicate
ByteArrayOptionPredicate
RuneArrayOptionPredicate
Float32ArrayOptionPredicate
Float64ArrayOptionPredicate
AnyArrayOptionPredicate
BoolListOptionPredicate
StringListOptionPredicate
IntListOptionPredicate
Int64ListOptionPredicate
ByteListOptionPredicate
RuneListOptionPredicate
Float32ListOptionPredicate
Float64ListOptionPredicate
AnyListOptionPredicate
BoolListPredicate
StringListPredicate
IntListPredicate
Int64ListPredicate
ByteListPredicate
RuneListPredicate
Float32ListPredicate
Float64ListPredicate
AnyListPredicate
BoolArrayListPredicate
StringArrayListPredicate
IntArrayListPredicate
Int64ArrayListPredicate
ByteArrayListPredicate
RuneArrayListPredicate
Float32ArrayListPredicate
Float64ArrayListPredicate
AnyArrayListPredicate
BoolOptionListPredicate
StringOptionListPredicate
IntOptionListPredicate
Int64OptionListPredicate
ByteOptionListPredicate
RuneOptionListPredicate
Float32OptionListPredicate
Float64OptionListPredicate
AnyOptionListPredicate
BoolListListPredicate
StringListListPredicate
IntListListPredicate
Int64ListListPredicate
ByteListListPredicate
RuneListListPredicate
Float32ListListPredicate
Float64ListListPredicate
AnyListListPredicate

[πŸ •]

Transformers

Transformers are functions which transform one type to other type A => B. Transformers are used as function's arguments in the following operations on monads: Map, FlatMap, GroupBy [πŸ •]

Identity

// Just return value without transformation
var IntIdentity func(int) int = func(i int) int { return i }
...

Examples:

l := MkIntList(1,2,3,1,3,3,4)

groups := l.GroupBy(IntIdentity)
/*
   Map(1 -> List(1,1),
       2 -> List(2),
       3 -> List(3,3,3),
       4 -> List(4))
*/

[πŸ •]

String transformers

// Build transformer which transform string to matched regex groups
func RegexGroups(r *regexp.Regexp) func(string) []string
func StringRegexGroups(pattern string) func(string) []string

Example:

l := MkStringList("10014-dav", "10015-pav", "10016-ant", "10017-din")


idNameRegex := StringRegexGroups("([0-9]+)\\-([a-z]+)") // string => []string transformer

res1 := l.MapStringArray(idNameRegex) 
/* StringArrayList (Array("10014-dav", "10014", "dav"),
                    Array("10015-pav", "10015", "pav"),
                    Array("10016-ant", "10016", "ant"),
                    Array("10017-din", "10017", "din")) */

[πŸ •]

Predef

Contains some convenient utils. [πŸ •]

Require

// Throws exception with message if e-condition is false
// Can be used as validation of public functions argument
func Require(e bool, msg string)

Examples:

func Div(a, b Int) Float32 {
  Require(a != 0, "Divide by zero!")
  ...
}

[πŸ •]

Concurrency API

Concurrence API implements a Future as abstraction over go routines and channels. It allows to combine async calculations in blocking and non blocking manner. All examples of this section use a IntFuture type. But this API is supported in the other future types also. (See Supported future types section)

Before using concurrence API library import the following packages:

import (
  . "github.com/zx80live/gofp/fp"
  . "github.com/zx80live/gofp/fp/concurrent"
)

[πŸ •]

Create future

// Execute go-routine for calculate function
func MkIntFuture(f func() Int) IntFuture

Example:

t1 := time.Now().Unix()
// create future
f1 := MkIntFuture(func() Int {
        time.Sleep(2 * time.Second)
        return Int(10)
      })
t2 := time.Now().Unix()
fmt.Println("at ", t2 - t1)      // at 0 milliseconds
                                 // microbenchmark demonstrates async running of IntFuture

// If you want to wait and get result of future use Result method
// Warning! But this method blocks current thread (routine)
t3 := time.Now().Unix()
res1 := f1.Result()
t4 := time.Now().Unix()

fmt.Println("result ", res1, "at ", t4 - t3)  // result 10 at 2 seconds 

[πŸ •]

Future.FlatMap

// Gives the ability to compose async operations together
func (f IntFuture) FlatMap<Type>(t func(Int) <Type>Future) <Type>Future

// examples
func (f IntFuture) FlatMapInt(t func(Int) IntFuture) IntFuture
func (f IntFuture) FlatMapString(t func(Int) StringFuture) StringFuture
...

[πŸ •]

Future.FlatMap.Blocking composition

FlatMap allows to compose two async calculations (which are presented as two futures) in the blocking manner. In other words, the resulting future will be result of sequential calculations of two futures. So the inner future which is mapped to outer future will be started when outer future will be completed. This example uses Future.Result invocation which is described in Future.Result section.

// Task: implement two async functions.
// Each function takes some time (2 seconds) and return some number.
// And then we should multiple results of these functions in blocking manner.
// Full time of execution both futures will be ~4000 milliseconds.
// Therefore these futures will be executed SEQUENTIALLY

t1 := time.Now().Unix()
f := MkIntFuture(func () Int {
       time.Sleep(2 * time.Second)                          // some payload emulation
       return Int(10)
     }).FlatMapInt(func (a Int) IntFuture  {
          return MkIntFuture(func () Int {
            time.Sleep(2 * time.Second)                     // some payload emulation
            return Int(a * 20)
           })
     })
t2 := time.Now().Unix()
fmt.Println("create and compose futures at", t2 - t1)       // at 0 milliseconds

t3 := time.Now().Unix()
// block current main-thread and wait and get result of future
var res1 Int = f.Result()                                   // 10 * 20
t4 := time.Now().Unix()
fmt.Println("get result of composing futures at", res1, t4 - t3)  // at 4 seconds
                                                                  // SEQUENTIAL execution

[πŸ •]

Future.FlatMap.NON-blocking composition

FlatMap allows to compose two async calculations (which are presented as two futures) in the non-blocking manner. In other words, the resulting future will be result of parallel calculations of two futures. So the both futures should be defined before than they will be composed via FlatMap. In this case they will be executed parallely. This example uses Future.Result invocation which is described in Future.Result section.

// Task: implement two async functions.
// Each function takes some time (2 seconds) and return some number.
// And then we should multiple results of these functions in NON-blocking manner.
// Full time of executions both futures will be ~2000 milliseconds.
// Therefore these futures will be executed PARALLEL

t1 := time.Now().Unix()
f1 := MkIntFuture(func () Int {
        time.Sleep(2 * time.Second)                         // some payload emulation
        return Int(10)
      })

f2 := MkIntFuture(func () Int {
        time.Sleep(2 * time.Second)                         // some payload emulation
        return Int(20)
      })

// compose futures in NON-blocking manner
var futureResult IntFuture = f1.FlatMapInt(func (a Int) IntFuture {
                                 return f2.MapInt(func (b Int) Int {
                                   return Int(a * b)
                                 })
                             })

t2 := time.Now().Unix()
fmt.Println("create and compose futures at", t2 - t1)       // at 0 milliseconds


t3 := time.Now().Unix()
// block current main-thread and wait and get result of future
var res1 Int = futureResult.Result()                        // 10 * 20
t4 := time.Now().Unix()
fmt.Println("get result of composing futures at", t4 - t3)  // at 2000 milliseconds
                                                            // PARALLEL execution
                                                            

[πŸ •]

Future.Map

// Transform content of the future
func (f IntFuture) Map<Type>(t func(Int) <Type>) <Type>Future

// examples
func (f IntFuture) MapInt(t func(Int) Int) IntFuture
func (f IntFuture) MapString(t func(Int) String) StringFuture
...

Example:

f1 := MkIntFuture(func() Int { return Int(10) })             // Future(10)

res1 := f1.MapInt(func(e Int) Int { return Int(e * 10) })      // Future(100)
res2 := f1.MapString(func(e Int) String { 
    return String(fmt.Sprintf("<%v>", e)) })                   // Future("<10>")

[πŸ •]

Future.Result

// Await and return the result of future
// This method blocks the current thread (routine) from which it was invoked
func (f IntFuture) Result() Int

Example:

t1 := time.Now().Unix()
f1 := MkIntFuture(func() Int { return Int(10) })  
f2 := MkIntFuture(func() Int { 
	time.Sleep(2 * time.Second)
	return Int(20) 
})                                
t2 := time.Now().Unix()

fmt.Println("create futures at ", t2 - t1)          // at ~0 milliseconds


t3 := time.Now().Unix()
res1 := f1.Result()                
t4 := time.Now().Unix()
fmt.Println("blocks current thread and return result of f1", res1," at ", res1, t4 - t3)   // at ~0 millis

t5 := time.Now().Unix()
res2 := f2.Result()                
t6 := time.Now().Unix()
fmt.Println("blocks current thread and return result of f2", res2, " at ", t6 - t5)   // at ~2000 millis

[πŸ •]

Future.Success

// Create already completed future with specified result
// Thus, it can be used when known result should be returned as future
func SuccessIntFuture(v Int) IntFuture

Example:

var f1 IntFuture = SuccessIntFuture(10)      // Future(10)

[πŸ •]

Supported future types

Supported future types (click to expand)
Future type Scala analogue
BoolFuture Future[Boolean]
StringFuture Future[String]
IntFuture Future[Int]
Int64Future Future[Long]
ByteFuture Future[Byte]
RuneFuture Future[Char]
Float32Future Future[Float]
Float64Future Future[Double]
AnyFuture Future[Any]
BoolOptionFuture Future[Option[Boolean]]
StringOptionFuture Future[Option[String]]
IntOptionFuture Future[Option[Int]]
Int64OptionFuture Future[Option[Long]]
ByteOptionFuture Future[Option[Byte]]
RuneOptionFuture Future[Option[Char]]
Float32OptionFuture Future[Option[Float]]
Float64OptionFuture Future[Option[Double]]
AnyOptionFuture Future[Option[Any]]
BoolListOptionFuture Future[Option[Boolean]]
StringListOptionFuture Future[Option[List[String]]]
IntListOptionFuture Future[Option[List[Int]]]
Int64ListOptionFuture Future[Option[List[Long]]]
ByteListOptionFuture Future[Option[List[Byte]]]
RuneListOptionFuture Future[Option[List[Char]]]
Float32ListOptionFuture Future[Option[List[Float]]]
Float64ListOptionFuture Future[Option[List[Double]]]
AnyListOptionFuture Future[Option[List[Any]]]
BoolArrayOptionFuture Future[Option[Array[Bool]]]
StringArrayOptionFuture Future[Option[Array[String]]]
IntArrayOptionFuture Future[Option[Array[Int]]]
Int64ArrayOptionFuture Future[Option[Array[Long]]]
ByteArrayOptionFuture Future[Option[Array[Byte]]]
RuneArrayOptionFuture Future[Option[Array[Char]]]
Float32ArrayOptionFuture Future[Option[Array[Float]]]
Float64ArrayOptionFuture Future[Option[Array[Double]]]
AnyArrayOptionFuture Future[Option[Array[Any]]]
BoolListFuture Future[List[Boolean]]
StringListFuture Future[List[String]]
IntListFuture Future[List[Int]]
Int64ListFuture Future[List[Long]]
ByteListFuture Future[List[Byte]]
RuneListFuture Future[List[Char]]
Float32ListFuture Future[List[Float]]
Float64ListFuture Future[List[Long]]
AnyListFuture Future[List[Any]]
BoolArrayFuture Future[Array[Boolean]]
StringArrayFuture Future[Array[String]]
IntArrayFuture Future[Array[Int]]
Int64ArrayFuture Future[Array[Long]]
ByteArrayFuture Future[Array[Byte]]
RuneArrayFuture Future[Array[Char]]
Float32ArrayFuture Future[Array[Float]]
Float64ArrayFuture Future[Array[Double]]
AnyArrayFuture Future[Array[Any]]

[πŸ •]

Bootstrap

Almost all code base of this library was generated by code-generator from the project gofp-bootstrap. That code generator is implemented in Scala language for the following reasons:

  • string interpolations
  • functional programming, etc

But the next generation of code generator can be implemented by the current gofp library. [πŸ •]

License

This library is distributed under MIT license found in the LICENSE file.

[πŸ •]