{"id":13471298,"url":"https://github.com/albrow/fo","last_synced_at":"2025-09-28T21:30:57.424Z","repository":{"id":144201831,"uuid":"120696128","full_name":"albrow/fo","owner":"albrow","description":"An experimental language which adds functional programming features to Go.","archived":true,"fork":false,"pushed_at":"2022-09-19T18:24:59.000Z","size":1979,"stargazers_count":1235,"open_issues_count":15,"forks_count":34,"subscribers_count":27,"default_branch":"master","last_synced_at":"2024-09-27T03:23:04.483Z","etag":null,"topics":["experimental-language","functional-programming","generic-functions","generic-types","golang","language"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/albrow.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}},"created_at":"2018-02-08T01:49:35.000Z","updated_at":"2024-09-13T11:32:20.000Z","dependencies_parsed_at":"2023-10-20T16:31:03.887Z","dependency_job_id":null,"html_url":"https://github.com/albrow/fo","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/albrow%2Ffo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/albrow%2Ffo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/albrow%2Ffo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/albrow%2Ffo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/albrow","download_url":"https://codeload.github.com/albrow/fo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234563141,"owners_count":18853060,"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":["experimental-language","functional-programming","generic-functions","generic-types","golang","language"],"created_at":"2024-07-31T16:00:42.778Z","updated_at":"2025-09-28T21:30:57.027Z","avatar_url":"https://github.com/albrow.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"# Fo\n\nFo is an experimental language which adds functional programming features to Go.\nThe name is short for \"Functional Go\".\n\n## Table of Contents\n\n\u003c!-- TOC depthFrom:2 depthTo:3 updateOnSave:false --\u003e\n\n- [Current Status](#current-status)\n- [Playground](#playground)\n- [Installation](#installation)\n- [Command Line Usage](#command-line-usage)\n- [Examples](#examples)\n- [Language Features](#language-features)\n  - [Generic Named Types](#generic-named-types)\n  - [Generic Functions](#generic-functions)\n  - [Generic Methods](#generic-methods)\n\n\u003c!-- /TOC --\u003e\n\n## Current Status\n\nFo is no longer being actively worked on or maintained.\n\nWhen this project was first created, Go did not support generics. However,\nas of [Go version 1.18](https://go.dev/doc/go1.18), that has changed. For\nmore information about how to use generics in the latest version of Go, see\n[this official tutorial](https://go.dev/doc/tutorial/generics).\n\nSince Go supports generics, there is much less reason to continue working on\nFo. It is sort of true that Fo supports some things that Go does not (like generic\nmethods or omitting the type parameters on a receiver type when it is not\nused). But overall Fo is still fairly unstable and has the major limitation of\nbeing restricted to compiling a single file. This likely makes it unsuitable for\nany real world applications.\n\nI have decided to leave this repository and [the playground](https://play.folang.org/)\nup for. It might be helpful for anyone who wants to hack on the Go compiler or work with\nASTs.\n\n## Playground\n\nIf you want to give Fo a try without installing anything, you can visit\n[The Fo Playground](https://play.folang.org/).\n\n## Installation\n\nThe Fo compiler is written in Go, so you can install it like any other Go\nprogram:\n\n```\ngo get -u github.com/albrow/fo\n```\n\n## Command Line Usage\n\nFor now, the CLI for Fo is extremely simple and only works on one file at a\ntime. There is only one command, `run`, and it works like this:\n\n```\nfo run \u003cfilename\u003e\n```\n\n`\u003cfilename\u003e` should be a source file ending in .fo which contains a `main`\nfunction.\n\n## Examples\n\nYou can see some example programs showing off various features of the language\nin the\n[examples directory](https://github.com/albrow/fo/tree/master/examples) of this\nrepository.\n\n## Language Features\n\nIn terms of syntax and semantics, Fo is a superset of Go. That means that any\nvalid Go program is also a valid Fo program (provided you change the file\nextension from \".go\" to \".fo\").\n\n### Generic Named Types\n\n#### Declaration\n\nFo extends the Go grammar for type declarations to allow the declaration of\ngeneric types. Generic types expect one or more \"type parameters\", which are\nplaceholders for arbitrary types to be specified later.\n\nThe extended grammar looks like this (some definitions omitted/simplified):\n\n```\nTypeDecl   = \"type\" identifier [ TypeParams ] Type .\nTypeParams = \"[\" identifier { \",\" identifier } \"]\" .\n```\n\nIn other words, type parameters should follow the type name and are surrounded\nby square brackets. Multiple type parameters are separated by a comma (e.g.,\n`type A[T, U, V]`).\n\nHere's the syntax for a generic `Box` which can hold a value of any arbitrary\ntype:\n\n```go\ntype Box[T] struct {\n\tv T\n}\n```\n\nType parameters are scoped to the type definition and can be used in place of\nany type. The following are all examples of valid type declarations:\n\n```go\ntype A[T] []T\n\ntype B[T, U] map[T]U\n\ntype C[T, U] func(T) U\n\ntype D[T] struct{\n\ta T\n\tb A[T]\n}\n```\n\nIn general, any named type can be made generic. The only exception is that Fo\ndoes not currently allow generic interface types.\n\n#### Usage\n\nWhen using a generic type, you must supply a number of \"type arguments\", which\nare specific types that will take the place of the type parameters in the type\ndefinition. The combination of a generic type name and its corresponding type\narguments is called a \"type argument expression\". The grammar looks like this\n(some definitions omitted/simplified):\n\n```\nTypeArgExpr = Type TypeArgs .\nTypeArgs    = \"[\" Type { \",\" Type } \"]\" .\n```\n\nLike type parameters, type arguments follow the type name and are surrounded by\nsquare brackets, and multiple type arguments are separated by a comma (e.g.\n`A[string, int, bool]`). In general, type argument expressions can be used\nanywhere you would normally use a type.\n\nHere's how we would use the `Box` type we declared above to initialize a `Box`\nwhich holds a `string` value:\n\n```go\nx := Box[string]{ v: \"foo\" }\n```\n\nFo does not currently support inference of type arguments, so they must always\nbe specified.\n\n### Generic Functions\n\n#### Declaration\n\nThe syntax for declaring a generic function is similar to named types. The\ngrammar looks like this:\n\n```\nFunctionDecl = \"func\" FunctionName [ TypeParams ] Signature [ FunctionBody ] .\nTypeParams   = \"[\" identifier { \",\" identifier } \"]\"\n```\n\nAs you might expect, type parameters follow the function name. Both the function\nsignature and body can make use of the given type parameters, and the type\nparameters will be replaced with type arguments when the function is used.\n\nHere's how you would declare a `MapSlice` function which applies a given\nfunction `f` to each element of `list` and returns the results.\n\n```go\nfunc MapSlice[T](f func(T) T, list []T) []T {\n\tresult := make([]T, len(list))\n\tfor i, val := range list {\n\t\tresult[i] = f(val)\n\t}\n\treturn result\n}\n```\n\n#### Usage\n\nJust like generic named types, to use a generic function, you must supply the\ntype arguments. If you actually want to call the function, just add the function\narguments after the type arguments. The grammar looks like this (some\ndefinitions omitted/simplified):\n\n```\nCallExpr = FunctionName ( TypeArgs ) Arguments .\nTypeArgs = \"[\" Type { \",\" Type } \"]\" .\n```\n\nHere's how you would call the `MapSlice` function we defined above:\n\n```go\nfunc incr(n int) int {\n\treturn n+1\n}\n\n// ...\n\nMapSlice[int](incr, []int{1, 2, 3})\n```\n\n### Generic Methods\n\n#### Declaration\n\nFo supports a special syntax for methods with a generic receiver type. You can\noptionally include the type parameters of the receiver type and those type\nparameters can be used in the function signature and body. Whenever a generic\nmethod of this form is called, the type arguments of the receiver type are\npassed through to the method definition.\n\nThe grammar for methods with generic receiver types looks like this (some\ndefinitions omitted/simplified):\n\n```\nMethodDecl = \"func\" Receiver MethodName [ TypeParams ] Signature [ FunctionBody ] .\nReceiver   = \"(\" [ ReceiverName ] Type [ TypeParams ] \")\" .\nTypeParams = \"[\" identifier { \",\" identifier } \"]\" .\n```\n\nHere's how we would define a method on the `Box` type defined above which makes\nuse of receiver type parameters:\n\n```go\ntype Box[T] struct {\n  v T\n}\n\nfunc (b Box[T]) Val() T {\n  return b.v\n}\n```\n\nYou can also omit the type parameters of the receiver type if they are not\nneeded. For example, here's how we would define a `String` method which does not\ndepend on the type parameters of the `Box`:\n\n```go\nfunc (b Box) String() string {\n  return fmt.Sprint(b.v)\n}\n```\n\nA method with a generic receiver can define additional type parameters, just\nlike a function. Here's an example of a method on `Box` which requires\nadditional type parameters.\n\n```go\nfunc (b Box[T]) Map[U] (f func(T) U) Box[U] {\n  return Box[U]{\n    v: f(b.v),\n  }\n}\n```\n\n#### Usage\n\nWhen calling methods with a generic receiver type, you do not need to specify\nthe type arguments of the receiver. Here's an example of calling the `Val`\nmethod we defined above:\n\n```go\nx := Box[string]{ v: \"foo\" }\nx.Val()\n```\n\nHowever, if the method declaration includes additional type parameters, you\nstill need to specify them. Here's how we would call the `Map` function\ndefined above to convert a `Box[int]` to a `Box[string]`.\n\n```go\ny := Box[int] { v: 42 }\nz := y.Map[string](strconv.Itoa)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falbrow%2Ffo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falbrow%2Ffo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falbrow%2Ffo/lists"}