{"id":13412902,"url":"https://github.com/seborama/fuego","last_synced_at":"2025-12-24T21:47:09.529Z","repository":{"id":33377432,"uuid":"156291371","full_name":"seborama/fuego","owner":"seborama","description":"Functional Experiment in Golang","archived":false,"fork":false,"pushed_at":"2024-04-13T13:49:08.000Z","size":1132,"stargazers_count":141,"open_issues_count":0,"forks_count":12,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-10-01T07:25:48.672Z","etag":null,"topics":["functional","functional-programming","go","golang","streams"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/seborama.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-11-05T22:24:09.000Z","updated_at":"2024-07-24T02:16:57.000Z","dependencies_parsed_at":"2024-06-18T22:40:04.501Z","dependency_job_id":"748e5d90-ee5b-487a-8f14-c443e34205d8","html_url":"https://github.com/seborama/fuego","commit_stats":null,"previous_names":[],"tags_count":37,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seborama%2Ffuego","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seborama%2Ffuego/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seborama%2Ffuego/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seborama%2Ffuego/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/seborama","download_url":"https://codeload.github.com/seborama/fuego/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221495314,"owners_count":16832458,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["functional","functional-programming","go","golang","streams"],"created_at":"2024-07-30T20:01:30.839Z","updated_at":"2025-12-24T21:47:09.523Z","avatar_url":"https://github.com/seborama.png","language":"Go","funding_links":[],"categories":["Functional","函数式编程","Relational Databases","Go","方法"],"sub_categories":["Search and Analytic Databases","SQL 查询语句构建库","Advanced Console UIs","检索及分析资料库"],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"doc/fuego_logo.png\" alt=\"ƒuego logo\" height=\"200\"\u003e\n\u003c/p\u003e\n\n\u003ch3 align=\"center\"\u003e\n  \u003ca href=\"#\"\u003eƒuego - Functional Experiment in Go\u003c/a\u003e\n\u003c/h3\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://twitter.com/intent/tweet?text=Fuego%20Go%20language%20functional%20experiment\u0026url=https://www.github.com/seborama/fuego\u0026hashtags=golang,functional,programming,developers\"\u003e\n    \u003cimg src=\"https://img.shields.io/twitter/url/http/shields.io.svg?style=social\" alt=\"Tweet\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://pkg.go.dev/github.com/seborama/fuego/v12\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/godoc-reference-blue.svg\" alt=\"fuego\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"http://goreportcard.com/report/seborama/fuego\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/go%20report-A%2B-brightgreen.svg\" alt=\"goreportcard\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://buymeacoff.ee/seborama/\" target=\"_blank\"\u003e\n  \u003cimg src=\"https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png\" alt=\"Buy Me A Coffee\" style=\"height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp\u003e\n  \u003ca style=\"vertical-align:middle; display:inline-block;\"\u003e\n  \u003cimg src=\"doc/fuego_code.png\" alt=\"ƒuego example\" width=\"440\"\u003e\n  \u003cimg align=\"right\" src=\"doc/fuego_code_employees.png\" alt=\"ƒuego example\" width=\"360\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n## Table of content\n\n- [Overview](#overview)\n- [Type Parameters](#type-parameters)\n- [Documentation](#documentation)\n- [Installation](#installation)\n- [Debugging](#debugging)\n- [Example Stream](#example-stream)\n- [Contributions](#contributions)\n- [The Golden rules of the game](#the-golden-rules-of-the-game)\n- [Pressure](#pressure)\n- [Concept: Entry](#concept-entry)\n- [Features summary](#features-summary)\n  - [Concurrency](#concurrency)\n- [Collectors](#collectors)\n- [Golang, Receivers and Functions](#golang-receivers-and-functions)\n- [Known limitations](#known-limitations)\n\n## [Overview](#overview)\n\n**_Making Go come to functional programming._**\n\nThis is a research project in functional programming which I hope will prove useful!\n\n___ƒ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.\n\nI hope you will find it useful!\n\nHave fun!!\n\n[(toc)](#table-of-content)\n\n## [Type Parameters](#type-parameters)\n\nStarting with version 11, ___ƒuego___ uses Go 1.18's [Type Parameters](https://go.googlesource.com/proposal/+/master/design/43651-type-parameters.md).\n\nIt is a drastic design change and fundamentally incompatible with previous versions of ___ƒuego___.\n\nUse version 10 or prior if you need the pre-Go1.18 version of ___ƒuego___ that is based on interface `Entry`.\n\n[(toc)](#table-of-content)\n\n## [Documentation](#documentation)\n\nThe code documentation and some examples can be found on [godoc](https://pkg.go.dev/github.com/seborama/fuego/v12).\n\nThe 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!\n\n\u003e **Note:**\n\u003e \u003cbr/\u003e\n\u003e Most tests use unbuffered channels to help detect deadlocks. In real life scenarios, it is recommended to use buffered channels for increased performance.\n\n[(toc)](#table-of-content)\n\n## [Installation](#installation)\n\n### Download\n\n```bash\ngo get github.com/seborama/fuego\n```\n\nOr for a specific version:\n\n```bash\ngo get gopkg.in/seborama/fuego.v12\n```\n\n### Import in your code\n\nYou can import the package in the usual Go fashion.\n\nTo simplify usage, you can use an alias:\n\n```go\npackage sample\n\nimport ƒ \"gopkg.in/seborama/fuego.v12\"\n```\n\n...or import as a blank import:\n\n```go\npackage sample\n\nimport _ \"gopkg.in/seborama/fuego.v12\"\n```\n\nNote: dot imports should work just fine but the logger may be disabled, unless you initialised the zap global logger yourself.\n\n[(toc)](#table-of-content)\n\n## [Debugging](#debugging)\n\nSet environment variable `FUEGO_LOG_LEVEL` to enable logging to the desired level.\n\n[(toc)](#table-of-content)\n\n## [Example Stream](#example-stream)\n\n```go\nstrs := []string{\n    \"a\",\n    \"b\",\n    \"bb\",\n    \"bb\",\n    \"cc\",\n    \"ddd\",\n}\n    \nCollect(\n  NewStreamFromSlice[string](strs, 100).\n    Filter(isString).\n    Distinct(stringHash),\n  GroupingBy(\n    stringLength,\n    Mapping(\n      stringToUpper,\n      Filtering(\n        stringLengthGreaterThan(1),\n        ToSlice[string](),\n      ),\n    ),\n  ),\n)\n\n// result: map[1:[] 2:[BB CC] 3:[DDD]]\n```\n\n[(toc)](#table-of-content)\n\n## [Contributions](#contributions)\n\nContributions and feedback are welcome.\n\nFor contributions, you must develop in TDD fashion and ideally provide Go testable examples (if meaningful).\n\nIf you have an idea to improve ___ƒuego___, please share it via an issue.\n\nAnd if you like ___ƒuego___ give it a star to show your support for the project - it will put a smile on my face! :blush:\n\nThanks!!\n\n[(toc)](#table-of-content)\n\n## [The Golden rules of the game](#the-golden-rules-of-the-game)\n\n1. Producers close their channel.\n\n1. Consumers do not close channels.\n\n1. Producers and consumers should be running in separate Go routines to prevent deadlocks when the channels' buffers fill up.\n\n[(toc)](#table-of-content)\n\n## [Pressure](#pressure)\n\nGo channels support buffering that affects the behaviour when combining channels in a pipeline.\n\nWhen 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.\n\nPresently, 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.\n\n[(toc)](#table-of-content)\n\n## [Features summary](#features-summary)\n\nStreams:\n\n- Stream:\n  - Filter\n  - Map / FlatMap\n  - Reduce\n  - GroupBy\n  - All/Any/None -Match\n  - Intersperse\n  - Distinct\n  - Head* / Last* / Take* / Drop*\n  - StartsWith / EndsWith\n  - ForEach / Peek\n  - ...\n- ComparableStream\n- MathableStream\n\nFunctional Types:\n\n- Optional\n- Predicate\n\nFunctions:\n\n- Consumer / BiConsumer\n- Function / BiFunction\n- StreamFunction\n\nCollectors:\n\n- GroupingBy\n- Mapping\n- FlatMapping\n- Filtering\n- Reducing\n- ToSlice\n- ToMap*\n\nCheck the [godoc](https://pkg.go.dev/github.com/seborama/fuego/v12) for full details.\n\n[(toc)](#table-of-content)\n\n### Concurrency\n\nAs of v8.0.0, a new concurrent model offers to process a stream concurrently while preserving order.\n\nThis is not possible yet with all Stream methods but it is available with e.g. `Stream.Map`.\n\n#### Notes on concurrency\n\nConcurrent 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.\n\n`Stream` has some methods that fan out (e.g. `ForEachC`). See the [godoc](https://pkg.go.dev/github.com/seborama/fuego/v12) for further information and limitations.\n\nI recommend Rob Pike's slides on Go concurrency patterns:\n\n- [Go Concurrency Patterns, Rob Pike, 2012](https://talks.golang.org/2012/concurrency.slide#1)\n\nAs a proof of concept and for facilitation, ___ƒuego___ has a `CStream` implementation to manage concurrently a collection of Streams.\n\n[(toc)](#table-of-content)\n\n## [Collectors](#collectors)\n\nA `Collector` is a mutable reduction operation, optionally transforming the accumulated result.\n\nCollectors can be combined to express complex operations in a concise manner.\n\u003cbr/\u003e\nSimply put, a collector allows the creation of bespoke actions on a Stream.\n\n___ƒuego___ exposes a number of functional methods such as `MapToInt`, `Head`, `LastN`, `Filter`, etc...\n\u003cbr/\u003e\nCollectors also provide a few functional methods.\n\nBut... what if you need something else? And it is not straightforward or readable when combining the existing methods ___ƒuego___ offers?\n\nEnters `Collector`: implement your own requirement functionally!\n\u003cbr/\u003e\nFocus on _**what**_ needs doing in your streams (and delegate the details of the _**how**_ to the implementation of your `Collector`).\n\n[(toc)](#table-of-content)\n\n## [Golang, Receivers and Functions](#golang-receivers-and-functions)\n\nSome tests (e.g. `TestCollector_Filtering`) are using receiver Getter methods in guise of `Function[T, R any]`. Here is the explanation how this is possible.\n\n`Function[T, R any]` is defined as `func(T) R`.\n\nA method Getter is typically defined as `func (T) Property() R {...}`.\n\nWith `t` as the receiver, Go allows `t.Property()` be called as `T.Property(t)`. This is a `func(T) R` and hence a `Function[T, R any]`.\n\nExample - `TestCollector_Filtering`:\n\n`employee.Department(employees[0])` is the same as `employees[0].Department()`, and of course, they both return a `string`.\n\nThe first syntax has one advantage for our purpose though: it is a `Function[T, R any]`.\n\n[(toc)](#table-of-content)\n\n## [Known limitations](#known-limitations)\n\n- several operations may be memory intensive or poorly performing.\n\n### No parameterised method in Go\n\nGo 1.18 brings typed parameters. However, parameterised methods are not allowed.\n\nThis prevents the Map() method of `Stream` from mapping to, and from returning, a new typed parameter.\n\nTo circumvent this, we need to use a decorator function to re-map the `Stream`.\n\nThis can lead to a leftward-growing chain of decorator function calls that makes the intent opaque:\n\n```go\nReStream(\n  ReStream(is, Stream[int]{}).Map(float2int),\n  Stream[string]{}).Map(int2string)\n// This is actually performing: Stream.Map(float2int).Map(int2string)\n```\n___ƒuego___ includes a set of casting functions that reduce the visually leftward-growing chain of decorators while preserving a natural functional flow expression:\n\n```go\nC(C(C(\n  s.\n    Map(float2int_), Int).\n    Map(int2string_), String).\n    Map(string2int_), Int).\n    ForEach(print[int])\n// This is actually performing: s.Map(float2int).Map(int2string).Map(string2int).ForEach(print)\n```\n\nWhile not perfect, this is the best workable compromise I have obtained thus far.\n\n[(toc)](#table-of-content)\n\n### Performance issues when using numerous parameterised methods in Go 1.18\n\nAs a result of this [issue](https://github.com/golang/go/issues/51957), an experiment to add `MapTo\u003cnative_type\u003e() Stream[\u003cnative_type\u003e]` is disabled.\n\nInstead, use function `CC` (ComparableStream Cast) to access Min(), Max(), and `MC` (MathableStream Cast) to access Sum().\n\n[(toc)](#table-of-content)\n\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://buymeacoff.ee/seborama/\" target=\"_blank\"\u003e\n  \u003cimg src=\"https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png\" alt=\"Buy Me A Coffee\" style=\"height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fseborama%2Ffuego","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fseborama%2Ffuego","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fseborama%2Ffuego/lists"}