{"id":15056452,"url":"https://github.com/hnc-agency/lazy","last_synced_at":"2025-04-10T04:10:49.031Z","repository":{"id":42995229,"uuid":"465380712","full_name":"hnc-agency/lazy","owner":"hnc-agency","description":"Lazy sequences for Erlang","archived":false,"fork":false,"pushed_at":"2022-03-24T08:28:52.000Z","size":93,"stargazers_count":9,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-24T05:26:25.461Z","etag":null,"topics":["erlang","lazy-sequences"],"latest_commit_sha":null,"homepage":"","language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hnc-agency.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}},"created_at":"2022-03-02T16:20:24.000Z","updated_at":"2025-02-27T18:09:21.000Z","dependencies_parsed_at":"2022-09-06T02:50:12.863Z","dependency_job_id":null,"html_url":"https://github.com/hnc-agency/lazy","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hnc-agency%2Flazy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hnc-agency%2Flazy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hnc-agency%2Flazy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hnc-agency%2Flazy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hnc-agency","download_url":"https://codeload.github.com/hnc-agency/lazy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247968269,"owners_count":21025796,"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":["erlang","lazy-sequences"],"created_at":"2024-09-24T21:51:36.586Z","updated_at":"2025-04-10T04:10:49.009Z","avatar_url":"https://github.com/hnc-agency.png","language":"Erlang","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Lazy\n\nLazy sequences for Erlang.\n\nErlang is an eager language. It materializes terms, including sequences\nsuch as lists, completely into memory at the point that you write them in\nthe code.\n\nOther functional languages such as Gleam, Clojure, or Haskell and\neven some non-functional languages such as Python know lazy sequences\nwhich generate items only when you access them.\n\n`lazy` provides a mechanism to use lazy sequences with Erlang.\n\nBe aware that lazy sequences are a two-edged sword, however. While they\nare more memory-friendly than eager sequences and _may_ yield more\nperformance given circumstances, they are also less predictable and\nharder to reason about, especially if your generators rely on side\neffects.\nUsed naively, large amounts of data may explode into memory if you use\nthem in a way that requires that a sequence must be materialized, and\nyou may also find yourself in an endless loop if you unwittingly run\ndown an infinite sequence, or both.\n\n## Generators\n\nGenerators are the key components that make lazy sequences possible.\nRather than concrete sequences consisting of concrete values, they\nare a recipe to generate values on the fly.\n\nA generator is a function producing the values making up a sequence,\none at a time.\nGenerators may produce bounded (finite) or unbounded (infinite) sequences.\n\nThere are no guarantees regarding to when and how often they will be called.\n\nThe next value of a generator can be generated with a call to\n`next/1`, which will either return the atom `empty` indicating\nthat the sequence is exhausted, or the current value and a new\ngenerator to access the next value in a tuple.\n\n### Built-in generators\n\n`lazy` comes with a collection of functions to create generators\nfor common use cases.\n\n* `append/2` and `append/3`\n* `apply/2`\n* `cycle/1`\n* `drop/2`\n* `dropwhile/2`\n* `empty/0`\n* `filter/2`\n* `filtermap/2`\n* `from_list/1`\n* `iterate/2`\n* `map/2`\n* `once/1`\n* `repeat/1`\n* `repeatedly/1`\n* `scan/3`\n* `seq/2` and `seq/3`\n* `reverse/1`\n* `take/2`\n* `takewhile/2`\n* `unfold/2`\n* `unzip/1`\n* `zip/2`\n* `zipwith/2` and `zipwith/3`\n\nSome of the listed functions, like `reverse/1`, should only be used with generators\nthat produce finite sequences.\n\n### Custom generators\n\nTo create a custom generator, you must devise a function of arity `0` which, when called,\nreturns either the atom `empty` to indicate that the generator is exhausted, or a 2-tuple\nconsisting of the generated value and a new function of the same design.\n\nThe following example generator produces the Fibonacci numbers.\n\n```erlang\nfib() -\u003e\n    fun () -\u003e fib1(0, 1) end.\n\nfib1(N1, N2) -\u003e\n    {N1 + N2, fun () -\u003e fib1(N2, N1 + N2) end}.\n```\n\nThe following example generator produces the Collatz sequence for a given number.\n\n```erlang\ncollatz(N) when is_integer(N), N \u003e 0 -\u003e\n    fun () -\u003e collatz1(N) end.\n\ncollatz1(1) -\u003e\n    lazy:once(1);\ncollatz1(N) when N rem 2 =:= 0 -\u003e\n    {N, fun () -\u003e collatz1(N div 2) end};\ncollatz1(N) -\u003e\n    {N, fun () -\u003e collatz1(3 * N + 1) end}.\n```\n\nThe following example generator produces the factorials, starting from 1.\n\n```erlang\nfact() -\u003e\n\tfun () -\u003e fact1(1, 1) end.\n\nfact1(N, Fact) -\u003e\n    {Fact, fun () -\u003e fact1(N + 1, (N + 1) * Fact) end}.\n```\n\n## Materializing\n\n`lazy` comes with a collection of functions to materialize generators into concrete\nterms. Such functions should only be used with generators that produce finite\nsequences.\n\n* `to_list/1`\n* `foldl/3` and `foldr/3`\n* `flush/1`\n* `all/2` and `any/2`\n* `length/1`\n\n## Warnings\n\nSpecial care must be taken with generators that do a fast-forward with a predicate\n(like `filter`, `filtermap` or `dropwhile`) when used on an infinite sequence.\n\nWith `filter` and `filtermap`, if the predicate never succeeds, a call to `next`\n(implicit or explicit) will hang forever.\n\n```erlang\n1\u003e Gen = `lazy:filter(fun (V) -\u003e is_atom(V) end, lazy:seq(1, infinity)).\n#Fun\u003clazy.16.33120069\u003e\n2\u003e lazy:next(Gen).\n... hangs\n```\n\nThe same is true for `dropwhile` if the predicate never fails.\n\n```erlang\n1\u003e Gen = lazy:dropwhile(fun (V) -\u003e is_integer(V) end, lazy:seq(1, infinity)).\n#Fun\u003clazy.13.33120069\u003e\n2\u003e lazy:next(Gen).\n... hangs\n```\n\n## Authors\n\n* Maria Scott (Maria-12648430)\n* Jan Uhlig (juhlig)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhnc-agency%2Flazy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhnc-agency%2Flazy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhnc-agency%2Flazy/lists"}