{"id":16613174,"url":"https://github.com/c-cube/iter","last_synced_at":"2026-03-16T05:01:51.769Z","repository":{"id":6615725,"uuid":"7859201","full_name":"c-cube/iter","owner":"c-cube","description":"Simple iterator abstract datatype, intended to iterate efficiently on collections while performing some transformations.","archived":false,"fork":false,"pushed_at":"2025-02-05T04:43:11.000Z","size":1479,"stargazers_count":123,"open_issues_count":3,"forks_count":12,"subscribers_count":12,"default_branch":"main","last_synced_at":"2025-03-29T06:02:33.838Z","etag":null,"topics":["higher-order-functions","iter","iterators","lazy","monad","ocaml","sequence","stream"],"latest_commit_sha":null,"homepage":"https://c-cube.github.io/iter","language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/c-cube.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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}},"created_at":"2013-01-27T22:38:43.000Z","updated_at":"2025-03-06T22:04:58.000Z","dependencies_parsed_at":"2023-11-16T04:31:08.068Z","dependency_job_id":"174ef3f6-7e18-4285-bed9-94c1e674e2f6","html_url":"https://github.com/c-cube/iter","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/c-cube%2Fiter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-cube%2Fiter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-cube%2Fiter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-cube%2Fiter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/c-cube","download_url":"https://codeload.github.com/c-cube/iter/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247299831,"owners_count":20916190,"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":["higher-order-functions","iter","iterators","lazy","monad","ocaml","sequence","stream"],"created_at":"2024-10-12T01:46:20.789Z","updated_at":"2025-12-23T03:04:39.910Z","avatar_url":"https://github.com/c-cube.png","language":"OCaml","funding_links":[],"categories":["\u003ca name=\"OCaml\"\u003e\u003c/a\u003eOCaml"],"sub_categories":[],"readme":"# Iter  ![build](https://github.com/c-cube/iter/workflows/build/badge.svg)\n\nClean and efficient loop fusion for all your iterating needs!\n\n\n```ocaml\n# #require \"iter\";;\n# let p x = x mod 5 = 0 in\n  Iter.(1 -- 5_000 |\u003e filter p |\u003e map (fun x -\u003e x * x) |\u003e fold (+) 0);;\n- : int = 8345837500\n```\n\n`Iter` is a simple abstraction over `iter` functions\nintended to iterate efficiently\non collections while performing some transformations. \nCommon operations supported by `Iter` include\n`filter`, `map`, `take`, `drop`, `append`, `flat_map`, etc.\n`Iter` is not designed to be as general-purpose or flexible as `Seq`. \nRather, it aims at providing a very simple and efficient\nway of iterating on a finite number of values, only allocating (most of the time)\none intermediate closure to do so. For instance, iterating on keys, or values,\nof a `Hashtbl.t`, without creating a list.\nSimilarly, the code above is turned into a single optimized\nfor loop with `flambda`.\n\n## Documentation\n\nThere is only one important type, `'a Iter.t`, and lots of functions built\naround this type.\nSee [the online API][doc]\nfor more details on the set of available functions.\nSome examples can be found below.\n\n[doc]: https://c-cube.github.io/iter/\n\nThe library used to be called `Sequence`.\nSome historical perspective is provided \nin [this talk](https://simon.cedeela.fr/assets/talks/sequence.pdf)\ngiven by @c-cube at some OCaml meeting.\n\n## Short Tutorial\n\n### Transferring Data\n\nConversion between n container types\nwould take n² functions. In practice, for a given collection\nwe can at best hope for `to_list` and `of_list`.\nWith iter, if the source structure provides a\n`iter` function (or a `to_iter` wrapper), it becomes:\n\n```ocaml\n# let q : int Queue.t = Queue.create();;\nval q : int Queue.t = \u003cabstr\u003e\n# Iter.( 1 -- 10 |\u003e to_queue q);;\n- : unit = ()\n# Iter.of_queue q |\u003e Iter.to_list ;;\n- : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]\n\n# let s : int Stack.t = Stack.create();;\nval s : int Stack.t = \u003cabstr\u003e\n# Iter.(of_queue q |\u003e to_stack s);;\n- : unit = ()\n# Iter.of_stack s |\u003e Iter.to_list ;;\n- : int list = [10; 9; 8; 7; 6; 5; 4; 3; 2; 1]\n```\n\nNote how the list of elements is reversed when we transfer them\nfrom the queue to the stack.\n\nAnother example is extracting the list of values of\na hashtable (in an undefined order that depends on the\nunderlying hash function):\n\n```ocaml\n# let h: (int, string) Hashtbl.t = Hashtbl.create 16;;\nval h : (int, string) Hashtbl.t = \u003cabstr\u003e\n# for i = 0 to 10 do\n     Hashtbl.add h i (string_of_int i)\n  done;;\n- : unit = ()\n\n# Hashtbl.length h;;\n- : int = 11\n\n# (* now to get the values *)\n  Iter.of_hashtbl h |\u003e Iter.map snd |\u003e Iter.to_list;;\n- : string list = [\"6\"; \"2\"; \"8\"; \"7\"; \"3\"; \"5\"; \"4\"; \"9\"; \"0\"; \"10\"; \"1\"]\n```\n\n### Replacing `for` loops\n\nThe `for` loop is a bit limited, and lacks compositionality.\nInstead, it can be more convenient and readable to\nuse `Iter.(--) : int -\u003e int -\u003e int Iter.t`.\n\n```ocaml\n# Iter.(1 -- 10_000_000 |\u003e fold (+) 0);;\n- : int = 50000005000000\n\n# let p x = x mod 5 = 0 in\n  Iter.(1 -- 5_000\n    |\u003e filter p\n    |\u003e map (fun x -\u003e x * x)\n    |\u003e fold (+) 0\n  );;\n- : int = 8345837500\n```\n\n**NOTE**: with _flambda_ under sufficiently strong\noptimization flags, such compositions of operators\nshould be compiled to an actual loop with no overhead!\n\n### Iterating on sub-trees\n\nA small λ-calculus AST, and some operations on it.\n\n```ocaml\n# type term =\n  | Var of string\n  | App of term * term\n  | Lambda of term ;;\ntype term = Var of string | App of term * term | Lambda of term\n\n# let rec subterms : term -\u003e term Iter.t =\n  fun t -\u003e\n    let open Iter.Infix in\n    Iter.cons t\n      (match t with\n      | Var _ -\u003e Iter.empty\n      | Lambda u -\u003e subterms u\n      | App (a,b) -\u003e\n        Iter.append (subterms a) (subterms b))\n  ;;\nval subterms : term -\u003e term Iter.t = \u003cfun\u003e\n\n# (* Now we can define many other functions easily! *)\n  let vars t =\n    Iter.filter_map\n      (function Var s -\u003e Some s | _ -\u003e None)\n      (subterms t) ;;\nval vars : term -\u003e string Iter.t = \u003cfun\u003e\n\n# let size t = Iter.length (subterms t) ;;\nval size : term -\u003e int = \u003cfun\u003e\n\n# let vars_list l = Iter.(of_list l |\u003e flat_map vars);;\nval vars_list : term list -\u003e string Iter.t = \u003cfun\u003e\n```\n\n### Permutations\n\nMakes it easy to write backtracking code (a non-deterministic\nfunction returning several `'a`\nwill just return a `'a Iter.t`).\nHere, we generate all permutations of a list by\nenumerating the ways we can insert an element in a list.\n\n```ocaml\n# open Iter.Infix;;\n# let rec insert x l = match l with\n  | [] -\u003e Iter.return [x]\n  | y :: tl -\u003e\n    Iter.append\n      (insert x tl \u003e|= fun tl' -\u003e y :: tl')\n      (Iter.return (x :: l)) ;;\nval insert : 'a -\u003e 'a list -\u003e 'a list Iter.t = \u003cfun\u003e\n\n# let rec permute l = match l with\n  | [] -\u003e Iter.return []\n  | x :: tl -\u003e permute tl \u003e\u003e= insert x ;;\nval permute : 'a list -\u003e 'a list Iter.t = \u003cfun\u003e\n\n# permute [1;2;3;4] |\u003e Iter.take 2 |\u003e Iter.to_list ;;\n- : int list list = [[4; 3; 2; 1]; [4; 3; 1; 2]]\n```\n\n### Advanced example\n\nThe module `examples/sexpr.mli` exposes the interface of the S-expression\nexample library. It requires OCaml\u003e=4.0 to compile, because of the GADT\nstructure used in the monadic parser combinators part of `examples/sexpr.ml`.\nBe careful that this is quite obscure.\n\n## Comparison with `Seq` from the standard library, and with `Gen`\n\n- `Seq` is an *external* iterator.\n  It means that the code which consumes\n  some iterator of type `'a Seq.t` is the one which decides when to\n  go to the next element. This gives a lot of flexibility, for example\n  when iterating on several iterators at the same time:\n\n  ```ocaml\n  let rec zip a b () = match a(), b() with\n    | Nil, _\n    | _, Nil -\u003e Nil\n    | Cons (x, a'), Cons (y, b') -\u003e Cons ((x,y), zip a' b')\n  ```\n\n- `Iter` is an *internal* iterator. When one wishes to iterate over\n  an `'a Iter.t`, one has to give a callback `f : 'a -\u003e unit`\n  that is called in succession over every element of the iterator.\n  Control is not handed back to the caller before the whole iteration is over.\n  This makes `zip` impossible to implement. However, the type `'a Iter.t`\n  is general enough that it can be extracted from any classic `iter` function,\n  including from data structures such as `Map.S.t` or `Set.S.t` or `Hashtbl.t`;\n  one cannot obtain a `'a Seq.t` from these without having access to the internal\n  data structure.\n\n- `Gen` (from [the gen library](http://github.com/c-cube/gen))\n  is an *external* iterator, like `Seq`, but it is imperative, mutable, and consumable\n  (you can't iterate twice on the same `'a Gen.t`).\n  It looks a lot like iterators in rust/java/… and can be pretty efficient in some cases.\n  Since you control iteration you can also write `map2`, `for_all2`, etc but\n  only with linear use of input generators (since you can traverse them only once).\n  That requires some trickery for cartesian_product (like storing already produced elements internally).\n\nIn short, `'a Seq.t` is more expressive than `'a Iter.t`, but it also\nrequires more knowledge of the underlying source of items.\nFor some operations such as `map` or `flat_map`, Iter is also extremely\nefficient and will, if flambda permits, be totally removed at\ncompile time (e.g. `Iter.(--)` becomes a for loop, and `Iter.filter`\nbecomes a if test).\n\nFor more details, you can read http://gallium.inria.fr/blog/generators-iterators-control-and-continuations/ or\nsee [the slides about Iter](https://simon.cedeela.fr/assets/talks/sequence.pdf)\nby me (c-cube) when `Iter` was still called `Sequence`.\n\n## Build\n\n1. via opam `opam install iter`\n2. manually (need OCaml \u003e= 4.02.0): `make all install`\n\nIf you have [qtest](https://github.com/vincent-hugot/qtest) installed,\nyou can build and run tests with\n\n```\n$ make test\n```\n\nIf you have [benchmarks](https://github.com/Chris00/ocaml-benchmark) installed,\nyou can build and run benchmarks with\n\n```\n$ make benchs\n```\n\nTo see how to use the library, check the following tutorial.\nThe `tests` and `examples` directories also have some examples, but they're a bit arcane.\n\n## License\n\nIter is available under the BSD license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc-cube%2Fiter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fc-cube%2Fiter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc-cube%2Fiter/lists"}