{"id":28454928,"url":"https://github.com/fsprojects/locsta","last_synced_at":"2025-07-31T19:02:45.815Z","repository":{"id":38991680,"uuid":"229113981","full_name":"fsprojects/LocSta","owner":"fsprojects","description":"An F# library for composing state-aware functions by @SchlenkR","archived":false,"fork":false,"pushed_at":"2023-11-25T13:56:02.000Z","size":1226,"stargazers_count":33,"open_issues_count":2,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-06-06T21:14:17.214Z","etag":null,"topics":["fsharp"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fsprojects.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":"2019-12-19T18:18:42.000Z","updated_at":"2023-11-25T13:55:23.000Z","dependencies_parsed_at":"2023-11-25T14:46:04.507Z","dependency_job_id":null,"html_url":"https://github.com/fsprojects/LocSta","commit_stats":null,"previous_names":["ronaldschlenker/fslocalstate"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/fsprojects/LocSta","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fsprojects%2FLocSta","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fsprojects%2FLocSta/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fsprojects%2FLocSta/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fsprojects%2FLocSta/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fsprojects","download_url":"https://codeload.github.com/fsprojects/LocSta/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fsprojects%2FLocSta/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262460312,"owners_count":23314712,"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":["fsharp"],"created_at":"2025-06-06T21:14:22.645Z","updated_at":"2025-06-28T16:32:57.918Z","avatar_url":"https://github.com/fsprojects.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# DISCONTINUED\n\n**LocSta is discontinued. Before starting to work with this library or thinking about forking it, please have a look at [Vide](https://github.com/vide-collabo/Vide), which is a successor of LocSta.**\n\n--------------------------\n\nLocSta\n===\n\nLocSta is authored by [@SchlenkR](https://github.com/ronaldschlenker). Feel free to leave a message.\n\n![build status](https://github.com/fsprojects/LocSta/actions/workflows/build_onPushMaster_onPullrequest.yml/badge.svg?event=push) ![test status](https://github.com/fsprojects/LocSta/actions/workflows/test_onPushMaster_onPullrequest.yml/badge.svg?event=push)\n\nLocSta is about\n\n\u003e Composing 'state-aware' functions as if they were just normal functions.\n\nWhat is state(ful) - from a programmers perspective?\n\n* State is a value that changes over time, so it *mutates*, and without mutation, it's not called state.\n* Usually, (local) state is represented by an instance of an object or a closure that captures a mutable value.\n* State must then have an 'identity', which is represented by a persistent location in memory - a pointer.\n* In order to use state from a computation, it means: It has to be created *up-front*, and it can be used *afterwards* by it's pointer.\n* The separation of *instanciation* and *usage* makes composition hard, or at least uncomfortable (besides other thinks that make compotion hard or uncomfortable).\n\nWhat is stateless?\n\n* It's the opposite of stateful, which means:\n* There is no mutation involved.\n* No need for objects, state capturing closures or pointers - there are just functions.\n* There is no persistence from one evaluation of a stateless computation to another.\n* No separation of *instanciation* and *usage*, which is comfortable to write: A function can be used ad-hoc (or in-place) where it should be used - there is no de-localization in code between state instanciation and usage.\n\n**LocSta aims to providing coding comfort in a way that stateful computations can be treated and composed as if they were stateless functions.**\n\nWhile this might sound like dealing with impure or internally mutable functions, it is based on a pure function approach. The focus lies on dealing with sequences of values. \n\nEven though many concepts overlap with `seq`, there are significant differences in behaviour and usage, as well as in the fundamental ideas.\n\n## Basic Examples\n\n```fsharp\n// There's currently no NuGet package available, so reference the dll directly.\n#r \"./src/LocSta/bin/Debug/netstandard2.0/LocSta.dll\"\n\nopen LocSta\nopen LocSta.Lib.Gen\n```\n\n\n**Count 2 values (use \"count\" as a stateful function)**\n\n* While `count` seems to be a pure function (there's no object instance or pointer to an object), it is stateful per se.\n* How does it work: The \"Local State\" CE evaluates the `count` functions, collects their state, and applies that state to the `count` functions again on subsequent evaluations.\n\n```fsharp\nloop {\n    let! v1 = count 0 1     // count from 0, increment by 1\n    let! v2 = count 100 5   // count from 100, increment by 5\n    yield v1 + v2\n}\n|\u003e Gen.toListn 4\n\n// [100; 106; 112; 118]\n```\n\n\n**\"Pairwise\" sequence processing**\n\n* The *pairwise* characteristics seen in the example above can also be applied to sequences.\n* Using the usual `seq` CE, the result woule be a cartesian product of sequence 1 and sequence 2\n\n```fsharp\nloop {\n    let! v1 = [ \"a\"; \"b\"; \"c\"; \"d\" ] |\u003e Gen.ofList\n    let! v2 = [  1 ;  2 ;  3 ;  4  ] |\u003e Gen.ofList\n    yield v1,v2\n}\n|\u003e Gen.toList\n\n// [(\"a\", 1); (\"b\", 2); (\"c\", 3); (\"d\", 4)]\n```\n\n\n**Controlling**\n\nIt is possible to explicitly control the workflow by emitting `Stop`, `Skip` and others:\n\n```fsharp\nloop {\n    let! v = count 0 1      // this would yield and never stop\n    if v = 5 then\n        return Loop.Skip    // we don't want '5' to be part of the result\n    elif v = 10 then\n        return Loop.Stop    // 'break' after 10 elements are yielded\n    else\n        yield v\n}\n|\u003e Gen.toList\n\n// [0; 1; 2; 3; 4; (* no 5 in here *) 6; 7; 8; 9]\n```\n\n\n**Writing stateful functions**\n\n* Until now, we only *used* stateful functions. But what if we want to *write* functions, and maintain a state?\n* Here's an example: Accumulate counted values, so that in each evaluation cycle, a list with all the counted values since beginning is yielded.\n* Instead of the `loop` builder, it uses the `feed` builder.\n\n```fsharp\nfeed {\n    let! state = Init []        // Place 'Init' on top of the computation and\n                                // give it a seed value (here: an empty list).\n                                // In the first evaluation, the seed value\n                                // will be returned, but in subsequent evaluations,\n                                // the 'newState' value will be returned.\n    \n    let! v = count 0 1\n    let accumulatedValues = v :: state\n    \n    let output = accumulatedValues |\u003e List.rev\n    let newState = accumulatedValues\n    \n    yield output, newState      // yield a tuple of the actual return value\n                                // and a state value.\n}\n|\u003e Gen.toListn 4\n\n//    [\n//        [0]\n//        [0; 1]\n//        [0; 1; 2]\n//        [0; 1; 2; 3]\n//    ]\n```\n\n## More Examples and Documentation\n\n**Tests**\n\nPlease have a look at [the base tests](./src/LocSta.Tests) for getting an impression of how the library works and maybe what it could be good for.\n\n**Previous versions**\n\nhttps://github.com/fsprojects/LocSta/tree/2360afbc45f646338e725b8059943dff3d41c5af\n\n**F# Applied Challenge**\n\nThe concept was also part of the F# Applied Challenge in 2019. Have a look ar the [contribution explanation](https://github.com/ronaldschlenker/applied_fsharp_challenge/tree/master/output/_htmlOutput) to find out more.\n\n\n\n# Current State of Development\n\n*This library is still experimental and volatile.*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffsprojects%2Flocsta","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffsprojects%2Flocsta","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffsprojects%2Flocsta/lists"}