Monad, Functional Programming features for Golang

Overview

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]
Issues
  • 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

    bug 
    opened by autodidacticon 2
  • 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

    bug enhancement 
    opened by hughjfchen 2
Releases(v2.3.0)
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.

Valentin Knabel 6 Jun 14, 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

Liam Mueller 1 Jun 12, 2022
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

Stew 20 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

Kemal Ogun Isik 0 Dec 2, 2021
Zach Howell 0 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

Qx 1 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.

fly.io 27 Mar 20, 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

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

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

wangwei 0 Feb 22, 2022
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

Vladimir Sibirov 1.4k Jun 24, 2022
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

PlebusSupremus1234 3 Nov 12, 2021
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

Max Chechel 61 Jun 21, 2022
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

Alexandre Fiori 106 Jun 24, 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

Krzysztof Wilczyński 12 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

null 176 Jun 10, 2022
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

null 29 Apr 16, 2022
Elastic is an Elasticsearch client for the Go programming language.

Elastic is an Elasticsearch client for the Go programming language.

Oliver Eilhard 6.9k Jun 26, 2022
👩🏼‍💻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

paco 26 May 26, 2022
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

Jesse Duffield 126 Jun 29, 2022