Monad, Functional Programming features for Golang

fpGo

tag Go Report Card codecov Travis CI Build Status GoDoc

license stars forks

Monad, Functional Programming features for Golang

Active Branches:

For Generics version(>=go1.18):generics

For NonGenerics version(<=go1.17):non-generics

Why

I love functional programing, Rx-style coding, and Optional usages.

However it's hard to implement them in Golang, and there're few libraries to achieve parts of them.

Thus I implemented fpGo. I hope you would like it :)

Features

  • Optional/Maybe

  • Monad, Rx-like

  • Publisher

  • Pattern matching

  • Fp functions

  • Java8Stream-like Collection

  • PythonicGenerator-like Coroutine(yield/yieldFrom)

  • Akka/Erlang-like Actor model(send/receive/spawn/states)

Special thanks

Usage

Optional (IsPresent/IsNil, Or, Let)

var m MaybeDef[interface{}]
var orVal int
var boolVal bool

// IsPresent(), IsNil()
m = Maybe.Just(1)
boolVal = m.IsPresent() // true
boolVal = m.IsNil() // false
m = Maybe.Just(nil)
boolVal = m.IsPresent() // false
boolVal = m.IsNil() // true

// Or()
m = Maybe.Just(1)
fmt.Println((m.Or(3))) // 1
m = Maybe.Just(nil)
fmt.Println((m.Or(3))) // 3

// Let()
var letVal int
letVal = 1
m = Maybe.Just(1)
m.Let(func() {
  letVal = 2
})
fmt.Println(letVal) // letVal would be 2

letVal = 1
m = Maybe.Just(nil)
m.Let(func() {
  letVal = 3
})
fmt.Println(letVal) // letVal would be still 1

MonadIO (RxObserver-like)

Example:

var m *MonadIODef[interface{}]
var actualInt int

m = MonadIO.Just(1)
actualInt = 0
m.Subscribe(Subscription[interface{}]{
  OnNext: func(in interface{}) {
    actualInt, _ = Maybe.Just(in).ToInt()
  },
})
fmt.Println(actualInt) // actualInt would be 1

m = MonadIO.Just(1).FlatMap(func(in interface{}) *MonadIODef[interface{}] {
  v, _ := Maybe.Just(in).ToInt()
  return MonadIO.Just(v + 1)
})
actualInt = 0
m.Subscribe(Subscription[interface{}]{
  OnNext: func(in interface{}) {
    actualInt, _ = Maybe.Just(in).ToInt()
  },
})
fmt.Println(actualInt) // actualInt would be 2

Stream (inspired by Collection libs)

Example:

" s = s.Distinct() tempString = "" for _, v := range s.ToArray() { tempString += Maybe.Just(v).ToMaybe().ToString() } fmt.Println(tempString) // tempString would be "1234"">
var s *StreamDef[interface{}]
var tempString = ""

s = StreamFromArray([]interface{}{}).Append(1).Extend(StreamFromInterface(2, 3, 4)).Extend(StreamFromArray([]interface{}{nil}))
tempString = ""
for _, v := range s.ToArray() {
  tempString += Maybe.Just(v).ToMaybe().ToString()
}
fmt.Println(tempString) // tempString would be "1234
   
    "
   
s = s.Distinct()
tempString = ""
for _, v := range s.ToArray() {
  tempString += Maybe.Just(v).ToMaybe().ToString()
}
fmt.Println(tempString) // tempString would be "1234"

Actor (inspired by Akka/Erlang)

Actor common(send/receive/spawn/states)

Example:

0 { for _, child := range self.children { child.Send(intVal) } } }) // Sequential Send messages(async) go func() { actorRoot.Send(cmdSpawn) actorRoot.Send(10) actorRoot.Send(cmdSpawn) actorRoot.Send(20) actorRoot.Send(cmdSpawn) actorRoot.Send(30) }() i := 0 for val := range resultChannel { intVal, _ := Maybe.Just(val).ToInt() actual += intVal i++ if i == 5 { go actorRoot.Send(cmdShutdown) } } // Result would be 1400 (=10*10+20*10+20*10+30*10+30*10+30*10) fmt.Println(actual)">
actual := 0
// Channel for results
resultChannel := make(chan interface{}, 1)
// Message CMDs
cmdSpawn := "spawn"
cmdShutdown := "shutdown"
// Testee
actorRoot := Actor.New(func(self *ActorDef[interface{}], input interface{}) {
  // SPAWN: for ROOT
  if input == cmdSpawn {
    self.Spawn(func(self *ActorDef[interface{}], input interface{}) {
      // SHUTDOWN: for Children
      if input == cmdShutdown {
        self.Close()
        return
      }

      // INT cases: Children
      val, _ := Maybe.Just(input).ToInt()
      resultChannel <- val * 10
    })
    return
  }
  // SHUTDOWN: for ROOT
  if input == cmdShutdown {
    for _, child := range self.children {
      child.Send(cmdShutdown)
    }
    self.Close()

    close(resultChannel)
    return
  }

  // INT cases: ROOT
  intVal, _ := Maybe.Just(input).ToInt()
  if intVal > 0 {
    for _, child := range self.children {
      child.Send(intVal)
    }
  }
})

// Sequential Send messages(async)
go func() {
  actorRoot.Send(cmdSpawn)
  actorRoot.Send(10)
  actorRoot.Send(cmdSpawn)
  actorRoot.Send(20)
  actorRoot.Send(cmdSpawn)
  actorRoot.Send(30)
}()

i := 0
for val := range resultChannel {
  intVal, _ := Maybe.Just(val).ToInt()
  actual += intVal

  i++
  if i == 5 {
    go actorRoot.Send(cmdShutdown)
  }
}

// Result would be 1400 (=10*10+20*10+20*10+30*10+30*10+30*10)
fmt.Println(actual)

Actor Ask (inspired by Akka/Erlang)

actorRoot := Actor.New(func(self *ActorDef[interface{}], input interface{}) {
    // Ask cases: ROOT
    switch val := input.(type) {
    case *AskDef[interface{}, int]:
        intVal, _ := Maybe.Just(val.Message).ToInt()

        // NOTE If negative, hanging for testing Ask.timeout
        if intVal < 0 {
            break
        }

        val.Reply(intVal * 10)
        break
    }
})

// var timer *time.Timer
var timeout time.Duration
timeout = 10 * time.Millisecond

// Normal cases
// Result would be 10
actual, _ = AskNewGenerics[interface{}, int](1).AskOnce(actorRoot, nil)
// Ask with Timeout
// Result would be 20
actual, _ = AskNewGenerics[interface{}, int](2).AskOnce(actorRoot, &timeout)
// Ask channel
// Result would be 30
ch := AskNewGenerics[interface{}, int](3).AskChannel(actorRoot)
actual = <- *ch
close(*ch)

// Timeout cases
// Result would be 0 (zero value, timeout)
actual, err = AskNewGenerics[interface{}, int](-1).AskOnce(actorRoot, &timeout)

Compose

Example:

var fn01 = func(args ...int) []int {
  val := args[0]
  return SliceOf(val + 1)
}
var fn02 = func(args ...int) []int {
  val := args[0]
  return SliceOf(val + 2)
}
var fn03 = func(args ...int) []int {
  val := args[0]
  return SliceOf(val + 3)
}

// Result would be 6
result := Compose(fn01, fn02, fn03)((0))[0]
Similar Resources

A modern programming language written in Golang.

MangoScript A modern programming language written in Golang. Here is what I want MangoScript to look like: struct Rectangle { width: number he

Nov 12, 2021

Unit tests generator for Go programming language

Unit tests generator for Go programming language

GoUnit GoUnit is a commandline tool that generates tests stubs based on source function or method signature. There are plugins for Vim Emacs Atom Subl

Jan 1, 2023

FreeSWITCH Event Socket library for the Go programming language.

eventsocket FreeSWITCH Event Socket library for the Go programming language. It supports both inbound and outbound event socket connections, acting ei

Dec 11, 2022

Simple interface to libmagic for Go Programming Language

File Magic in Go Introduction Provides simple interface to libmagic for Go Programming Language. Table of Contents Contributing Versioning Author Copy

Dec 22, 2021

A library for parallel programming in Go

pargo A library for parallel programming in Go Package pargo provides functions and data structures for expressing parallel algorithms. While Go is pr

Nov 28, 2022

The Gorilla Programming Language

The Gorilla Programming Language

Gorilla Programming Language Gorilla is a tiny, dynamically typed, multi-engine programming language It has flexible syntax, a compiler, as well as an

Apr 16, 2022

Elastic is an Elasticsearch client for the Go programming language.

Elastic is an Elasticsearch client for the Go programming language.

Jan 9, 2023

👩🏼‍💻A simple compiled programming language

👩🏼‍💻A simple compiled programming language

The language is written in Go and the target language is C. The built-in library is written in C too

Nov 29, 2022

Welcome to the future of programming languages: OK?

Welcome to the future of programming languages: OK?

OK? Try it out on the playground OK?'s mascot: Quentyn Questionmark. Programming Is Simple Again OK? is a modern, dynamically typed programming langua

Jan 1, 2023
Comments
  • go.mod does not comply with semantic versioning

    go.mod does not comply with semantic versioning

      go get github.com/TeaEntityLab/[email protected]
    go: github.com/TeaEntityLab/[email protected]: invalid version: module contains a go.mod file, so module path must match major version ("github.com/TeaEntityLab/fpGo/v2")
    
    

    Is this project's go.mod correct?

    https://github.com/golang/go/issues/35732

  • interface{} does not implement comparable [InvalidTypeArg]

    interface{} does not implement comparable [InvalidTypeArg]

    I've been just trying to explore FP in go and found this. I tried to open the code but met following error: interface{} does not implement comparable [InvalidTypeArg]

    The code has such an error is in stream.go: // StreamFromInterface New Stream instance from an array func StreamFromInterface(list ...interface{}) *StreamDef[interface{}] { return StreamFromArray(list) } Line 17 to line 21

    I'm using go 1.18 on MacOs 12.3

Lithia is an experimental functional programming language with an implicit but strong and dynamic type system.

Lithia is an experimental functional programming language with an implicit but strong and dynamic type system. Lithia is designed around a few core concepts in mind all language features contribute to.

Dec 24, 2022
Go module that provides primitive functional programming utilities.

Functional Functional provides a small set of pure functions that are common in functional programming languages, such as Reduce, Map, Filter, etc. Wi

Jun 12, 2022
The package manager for macOS you didn’t know you missed. Simple, functional, and fast.
The package manager for macOS you didn’t know you missed. Simple, functional, and fast.

Stew The package manager for macOS you didn’t know you missed. Built with simplicity, functionality, and most importantly, speed in mind. Installation

Mar 30, 2022
Advent of Code is an Advent calendar of small programming puzzles for a variety of skill sets and skill levels that can be solved in any programming language you like.

Advent of Code 2021 Advent of Code is an Advent calendar of small programming puzzles for a variety of skill sets and skill levels that can be solved

Dec 2, 2021
Jan 4, 2022
skiptable is a jump table that mimics redis' zset using go, and implements most of the features of redis zset

skiptable is a jump table that mimics redis' zset using go, and implements most of the features of redis zset

Oct 25, 2021
dropspy is a (POC-quality) reworking of the C-language dropwatch tool in Go, with some extra features.

dropspy is a (POC-quality) reworking of the C-language dropwatch tool in Go, with some extra features.

Dec 12, 2022
Go package that adds marshal and unmarshal features to nullable sql types.

#Nullable Very simple Go module to handle nullable fields. Basically, it adds to sql package types the JSON marshal and unmarshal features. It has 100

Jan 20, 2022
Orders - An example of gin contains many useful features
Orders - An example of gin contains many useful features

Go Gin Example An example of gin contains many useful features 简体中文 Installation

Feb 22, 2022
Flow-based and dataflow programming library for Go (golang)
Flow-based and dataflow programming library for Go (golang)

GoFlow - Dataflow and Flow-based programming library for Go (golang) Status of this branch (WIP) Warning: you are currently on v1 branch of GoFlow. v1

Dec 30, 2022