{"id":25195869,"url":"https://github.com/s-expressionists/khazern","last_synced_at":"2026-01-18T06:10:48.643Z","repository":{"id":105027445,"uuid":"297996684","full_name":"s-expressionists/Khazern","owner":"s-expressionists","description":"A portable and extensible Common Lisp LOOP implementation","archived":false,"fork":false,"pushed_at":"2024-06-04T18:31:21.000Z","size":740,"stargazers_count":7,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-10T01:38:42.434Z","etag":null,"topics":["common-lisp","extensible","portable"],"latest_commit_sha":null,"homepage":"","language":"Common Lisp","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/s-expressionists.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","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":"2020-09-23T14:29:03.000Z","updated_at":"2024-11-30T16:43:06.000Z","dependencies_parsed_at":"2023-10-23T20:29:24.830Z","dependency_job_id":null,"html_url":"https://github.com/s-expressionists/Khazern","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/s-expressionists%2FKhazern","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/s-expressionists%2FKhazern/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/s-expressionists%2FKhazern/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/s-expressionists%2FKhazern/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/s-expressionists","download_url":"https://codeload.github.com/s-expressionists/Khazern/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247208020,"owners_count":20901568,"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":["common-lisp","extensible","portable"],"created_at":"2025-02-10T01:38:54.343Z","updated_at":"2026-01-18T06:10:48.630Z","avatar_url":"https://github.com/s-expressionists.png","language":"Common Lisp","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Khazern\n\nKhazern is a portable and extensible Common Lisp LOOP\nimplementation. It was originally written by Robert Strandh as part of\n[SICL][]. It can be loaded intrinsically in order to replace LOOP in\nan existing Lisp implementation or extrinsically to coexist with the\nimplementation's own LOOP. Khazern is available via [Quicklisp][],\n[ocicl][] or [Ultralisp][].\n\nTo load Khazern intrinsically do the following:\n\n```common-lisp\n(asdf:load-system \"khazern-intrinsic\")\n; WARNING: redefining COMMON-LISP:LOOP-FINISH in DEFMACRO\n; WARNING: redefining COMMON-LISP:LOOP in DEFMACRO\n; =\u003e T\n\n(loop for i in '(1 2 3 4) when (oddp i) collect i)\n; =\u003e (1 3)\n```\n\nTo load Khazern extrinsically do the following\n\n```common-lisp\n(asdf:load-system \"khazern-extrinsic\")\n; =\u003e T\n\n(khazern-extrinsic:loop for i in '(1 2 3 4) when (oddp i) collect i)\n; =\u003e (1 3)\n```\n\nKhazern also implements an extended LOOP syntax via the\nkhazern-extension-extrinsic and khazern-extension-intrinsic systems.\n\n```common-lisp\n(asdf:load-systems \"khazern-extension-extrinsic\" \"flexi-streams\")\n; =\u003e NIL\n\n(kee:loop for i being the elements in #(1 2 3 4 5)\n            start 1 from-end t\n          do (format t \"~w~%\" i))\n; 5\n; 4\n; 3\n; 2\n; =\u003e NIL\n\n(with-input-from-string (stream \"a 233d0 #C(1 2) (wibble)\")\n  (kee:loop for i being the objects in stream\n            do (format t \"~w~%\" i)))\n; A\n; 233.0d0\n; #C(1 2)\n; (WIBBLE)\n; =\u003e NIL\n\n(with-input-from-string (stream \"abcd\")\n  (kee:loop for i being the characters in stream\n            do (format t \"~w~%\" i)))\n; #\\a\n; #\\b\n; #\\c\n; #\\d\n; =\u003e NIL\n\n(with-input-from-string (stream \"ab\nc\nd\")\n  (kee:loop for i being the lines in stream\n              using (missing-newline-p j)\n            do (format t \"~w ~w~%\" i j)))\n; \"ab\" NIL\n; \"c\" NIL\n; \"d\" T\n; =\u003e NIL\n\n(flexi-streams:with-input-from-sequence (stream #(1 2 3))\n  (kee:loop for i being the bytes in stream\n            do (format t \"~w~%\" i)))\n; 1\n; 2\n; 3\n; =\u003e NIL\n```\n\n## Replacing Builtin LOOP with Khazern\n\nReplacing a Common Lisp's LOOP implementation with Khazern can be done\nwith the khazern-intrinsic system. This system is actually intended\nfor use as the CL implementation's original LOOP implementation.\nBecause LOOP is in the COMMON-LISP package ASDF logic regarding\nrecompilation of systems dependent on khazern-intrinsic may not be\nreliable. Instead if one wants to use Khazern as the LOOP\nimplementation in a system it is better to use khazern-extrinsic and\nthen SHADOWING-IMPORT-FROM in DEFPACKAGE.\n\n```common-lisp\n;;; quux.asd\n\n\n(asdf:defsystem \"quux\"\n  :depends-on ((:feature (:not :loop/khazern) \"khazern-extrinsic\"))\n  :components ((:file \"quux\")))\n\n;;; quux.lisp\n\n(cl:defpackage #:quux\n  (:use #:common-lisp)\n  #-loop/khazern\n  (:shadowing-import-from #:khazern-extrinsic\n                          #:loop\n                          #:loop-finish))\n\n(cl:in-package #:quux)\n\n(defun wibble (s)\n  (loop for i across s\n        do (print i)))\n```\n\nThe feature expressions involving `loop/khazern` avoid using\nkhazern-extrinsic if the CL implementation uses Khazern as its LOOP\nprovider. Currently SICL and Clasp use Khazern in this way.\n\nTo use the extension system one need only replace the dependency in\nthe ASD file.\n\n```common-lisp\n;;; quux.asd\n\n\n(asdf:defsystem \"quux\"\n  :depends-on ((:feature (:not :loop/khazern-extension) \"khazern-extension-extrinsic\"))\n  :components ((:file \"quux\")))\n\n;;; quux.lisp\n\n(cl:defpackage #:quux\n  (:use #:common-lisp)\n  #-loop/khazern-extension\n  (:shadowing-import-from #:khazern-extension-extrinsic\n                          #:loop\n                          #:loop-finish))\n\n(cl:in-package #:quux)\n\n(defun wibble (s)\n  (loop for i being the elements in s\n        do (print i)))\n```\n\nThe feature expressions involving `loop/khazern-extension` perform the\nsame role as the feature expressions involving `loop/khazern` in the\nprevious example. Currently Clasp uses khazern-extension.\n\n## Khazern Extensions\n\nThe orignal Technical Memo 169 \"Loop Iteration Macro\" which defined\nLOOP for Lisp Machine Lisp and Maclisp also specified an extension\nmechanism known as an \"iteration path.\" The syntax was roughly:\n\n```\nfor-as-iteration-path ::= {FOR | AS} var [type-spec] BEING\n                          {path-exclusive | path-inclusive}\n                          {path-using | path-preposition}*\npath-exclusive        ::= {EACH | THE} path-name\npath-inclusive        ::= form AND {ITS | EACH | HIS | HER}\n                          path-name\npath-using            ::= USING ({using-name var [type-spec]}+)\npath-preposition      ::= preposition-name form\npreposition-name      ::= name\nusing-name            ::= simple-var\npath-name             ::= symbol\n```\n\nInclusive iteration paths are those in which the initial value of\n`var` was `form` itself. An example given in the Lisp Machine Manual\nis that of the CDRS iteration path:\n\n```common-lisp\n(loop for x being the cdrs of '(a b c . d) collect x)\n; =\u003e ((b c . d) (c . d) d)\n\n(loop for x being '(a b c . d) and its cdrs collect x)\n; =\u003e ((a b c . d) (b c . d) (c . d) d)\n```\n\nUsage of inclusive iteration path seems to have been rare even in the\nLisp Machine Lisp. The mechanism is still exists in many CL\nimplementations but is completely unused in modern code. Only the\nresidual syntax of exclusive iteration paths survived in the ANSI CL\nspecification. For this reason, Khazern only supports exclusive\niteration path extensions. Khazern's syntax is:\n\n```\nfor-as-being     ::= {FOR | AS} var [type-spec] BEING {EACH | THE}?\n                     name {path-using | path-preposition}*\npath-using       ::= USING ({using-name var [type-spec]}+)\npath-preposition ::= preposition-name form\npreposition-name ::= name\nusing-name       ::= simple-var\nname             ::= symbol\n```\n\nIn the original path iteration syntax EACH or THE is needed to\ndistinguish between inclusive and exclusive paths. Since Khazern\ndoesn't have inclusive paths, the EACH and THE tokens are made\noptional. Also, path-using permits optional type-specs which was not\nallowed in the original iteration path implementations.\n\nKhazern supports many extensions mechanisms in addition to iteration\npaths. The primary interface to adding extensions is PARSE-CLAUSE\nwhich takes as one of its arguments a REGION that specifies where in\nLOOP the clause is permitted. Currently there are the following\nregions:\n\n* body-region - top-level clauses in LOOP.\n* selectable-region - clauses that can occur in conditionals or as\n  top-level clauses.\n* for-as-region - subclauses of FOR or AS.\n* being-region - subclauses of FOR-BEING or AS-BEING.\n* with-region - subclauses of WITH.\n\nThis makes iteration paths valid in the being-region as so Khazern\nrefers to these as being clauses.\n\nThen khazern-extension-extrinsic and khazern-extension-intrinsic\nsystems implement many predefined extensions. They are described\nin the sections below.\n\n### Hash Table Iteration\n\n#### HASH-KEYS Being Clause\n\nThe HASH-KEYS being clause is identical to that described in the ANSI\nCL specification with the addition of the ability to specify a\ntype-spec for USING variable.\n\n```\npath-name        ::= {HASH-KEY | HASH-KEYS}\npreposition-name ::= {IN | OF}\nusing-name       ::= {HASH-VALUE}\n```\n\n##### Examples\n\n```common-lisp\n(kee:loop for v being each hash-value of (alexandria:plist-hash-table '(\"a\" 1 \"b\" 2 \"c\" 3))\n            using (hash-key k of-type string)\n          collect (cons k v))\n; =\u003e ((\"a\" . 1) (\"b\" . 2) (\"c\" . 3))\n```\n\n#### HASH-VALUES Being Clause\n\nThe HASH-VALUES being clause is identical to that described in the\nANSI CL specification with the addition of the ability to specify a\ntype-spec for USING variable.\n\n```\npath-name        ::= {HASH-VALUE | HASH-VALUES}\npreposition-name ::= {IN | OF}\nusing-name       ::= {HASH-KEY}\n```\n\n##### Examples\n\n```common-lisp\n(kee:loop for k being each hash-key of (alexandria:plist-hash-table '(\"a\" 1 \"b\" 2 \"c\" 3))\n            using (hash-value v of-type integer)\n          collect (cons k v))\n; =\u003e ((\"a\" . 1) (\"b\" . 2) (\"c\" . 3))\n```\n\n#### ENTRIES Being Clause\n\nThe dictionary entry for MAPHASH has the statement that it \"Iterates\nover all entries in the hash-table.\" In other words the key value\npairs are considered an iterable quantity known as an \"entry.\" This\nmakes the HASH-KEYS and HASH-VALUES being clauses seem a bit awkward\nwith their USING syntax. The original iteration path mechanism treated\nUSING as a way to access internal loop variables or at best auxilary\nvariables. The hash keys or values are not really auxilary values.\n\nTo emphasize the \"entry\" concept for hash tables and simply the loop\nsyntax for hash tables, Khazern supplies the ENTRIES being clause. The\nstepping variable has the value of a list with the first element set\nto the hash table key and the second element set to the hash table\nvalue. This enables LOOP's built in destructuring to handle the\nextraction.\n\n```\npath-name        ::= {ENTRY | ENTRIES}\npreposition-name ::= {IN | OF}\nusing-name       ::= {}\n```\n\nThe ENTRIES being clause also has an abbreviated form via the OF\ntoken.\n\n```\nfor-as-entries  ::= {FOR | AS} var [type-spec] OF form\n```\n\n##### Examples\n\n```common-lisp\n(kee:loop for (k v) being entries of ht\n          collect k collect v)\n; =\u003e (:FU :BAR :BAZ :QUUX)\n\n(kee:loop for (k v) of ht\n          collect k collect v)\n; =\u003e (:FU :BAR :BAZ :QUUX)\n\n(kee:loop for (k v) of-type (symbol symbol) being entries of ht\n          collect k collect v)\n; =\u003e (:FU :BAR :BAZ :QUUX)\n\n(kee:loop for kv being entries of ht\n          nconc kv)\n; =\u003e (:FU :BAR :BAZ :QUUX)\n```\n\n### Package Symbol Iteration\n\n#### SYMBOLS, PRESENT-SYMBOLS, and EXTERNAL-SYMBOLS Being Clauses\n\nSYMBOLS, PRESENT-SYMBOLS, and EXTERNAL-SYMBOLS being clauses are\nidentical to that described in the ANSI CL specification except they\npermit the IN/OF preposition form to be a list of package designators\nas WITH-PACKAGE-ITERATOR does. They also add the ASSESSIBILITY-TYPE\nand PACKAGE USING variables to access those values returned by the\npackage iterator.\n\n```\npath-name        ::= {SYMBOL | SYMBOLS | PRESENT-SYMBOL |\n                      PRESENT-SYMBOLS | EXTERNAL-SYMBOL |\n                      EXTERNAL-SYMBOLS}\npreposition-name ::= {IN | OF}\nusing-name       ::= {ACCESSIBILITY-TYPE | PACKAGE}\n```\n\n##### Examples\n\n```common-lisp\n(kee:loop for sym being each symbol in '(:common-lisp :keyword)\n            using (accessibility-type acc package pkg)\n          repeat 10                                 \n          do (format t \"~w ~w ~w~%\" sym acc pkg))\n; PAIRLIS :EXTERNAL #\u003cPACKAGE \"COMMON-LISP\"\u003e\n; ACOSH :EXTERNAL #\u003cPACKAGE \"COMMON-LISP\"\u003e\n; FILE-WRITE-DATE :EXTERNAL #\u003cPACKAGE \"COMMON-LISP\"\u003e\n; BUILT-IN-CLASS :EXTERNAL #\u003cPACKAGE \"COMMON-LISP\"\u003e\n; *READTABLE* :EXTERNAL #\u003cPACKAGE \"COMMON-LISP\"\u003e\n; MACROEXPAND-1 :EXTERNAL #\u003cPACKAGE \"COMMON-LISP\"\u003e\n; TERPRI :EXTERNAL #\u003cPACKAGE \"COMMON-LISP\"\u003e\n; LOOP-FINISH :EXTERNAL #\u003cPACKAGE \"COMMON-LISP\"\u003e\n; PSETF :EXTERNAL #\u003cPACKAGE \"COMMON-LISP\"\u003e\n; METHOD-COMBINATION :EXTERNAL #\u003cPACKAGE \"COMMON-LISP\"\u003e\n; =\u003e NIL\n```\n\n### Sequence Iteration\n\n#### ELEMENTS Being Clause\n\nThe ELEMENTS being clause iterates over sequences or\nmultidimensional arrays. If the extensible sequence protocol is\navailable it will use MAKE-SEQUENCE-ITERATOR from that protocol for\nsequences. Otherwise it will attempt to use an efficient sequence\nspecific iterator with ELT as the fallback iterator.\n\n```\npath-name        ::= {ELEMENT | ELEMENTS}\npreposition-name ::= {IN | OF | START | END | FROM-END}\nusing-name       ::= {INDEX | INDICES}\n```\n\n* The IN and OF prepositions are synonyms and specify the form that\n  evaluates to the sequence. One of these prepositions is required.\n* The START preposition specifies the starting index of the\n  iteration. It is optional and if not specified it will default to 0.\n* The END preposition specifies the ending index of the iteration. It\n  is optional and if not specified it will default to the sequence\n  length.\n* The FROM-END preposition specifies the iteration direction. If it is\n  non-NIL then iteration will go from END to START. Otherwise\n  iteration will go from START to END. It is optional and if not\n  specified it will default to NIL.\n* The INDEX or INDICES phrases in USING names a variable or a list of\n  variables, in the case of multidimensional arrays, to store the\n  current iteration index. It is optional.\n\nThe ELEMENTS being clause also has an abbreviated form via the OVER\ntoken.\n\n```\nfor-as-elements  ::= {FOR | AS} var [type-spec] OVER form\n                     {path-using | path-preposition}*\npath-using       ::= USING ({using-name var [type-spec]}+)\npath-preposition ::= preposition-name form\npreposition-name ::= {START | END | FROM-END}\nusing-name       ::= {INDEX | INDICES}\n```\n\n#### Examples\n\n```common-lisp\n(kee:loop for i being the elements in #(1 2 3 4 5)\n          collect i)  \n; =\u003e (1 2 3 4 5)\n\n(kee:loop for i being the elements in #(1 2 3 4 5)\n            from-end t\n          collect i)\n; =\u003e (5 4 3 2 1)\n\n(kee:loop for i being the elements in #(1 2 3 4 5)\n            start 1\n          collect i)\n; =\u003e (2 3 4 5)\n\n(kee:loop for i being the elements in #(1 2 3 4 5)\n            start 1 from-end t end 3 \n          collect i)\n; =\u003e (3 2)\n\n(kee:loop for i being the elements in \"abcde\"\n            from-end t using (index j)\n          collect (cons j i))\n; =\u003e ((4 . #\\e) (3 . #\\d) (2 . #\\c) (1 . #\\b) (0 . #\\a))\n\n(kee:loop for i being each element of #2A((1 2) (3 4) (5 6))\n            using (indices (j k))\n          collect (list i j k))\n; =\u003e ((1 0 0) (2 0 1) (3 1 0) (4 1 1) (5 2 0) (6 2 1))\n\n(kee:loop for i over \"abcde\" using (index j)\n          collect (cons j i))\n; =\u003e ((0 . #\\a) (1 . #\\b) (2 . #\\c) (3 . #\\d) (4 . #\\e))\n```\n\n### Stream Iteration\n\nAll stream being clauses have the following prepositions and USING\nphrases:\n\n* The IN and OF prepositions are synonyms and specify the form that\n  evaluates to the stream. If one of these prepositions is not\n  specified then \\*STANDARD-INPUT\\* is used.\n* The CLOSE preposition specifies whether the stream should be closed\n  when the LOOP is terminated. If it is non-NIL then the stream is\n  closed via UNWIND-PROTECT when the loop terminates. It is optional\n  and if not specified it will default to NIL\n* The STREAM phrase in USING names a variable to store the current\n  stream. It is optional.\n\n#### BYTES Being Clause\n\nThe BYTES being clause iterates over an input stream using\nREAD-BYTE. It terminates on EOF.\n\n```\npath-name        ::= {BYTE | BYTES}\npreposition-name ::= {IN | OF | CLOSE}\nusing-name       ::= {STREAM}\n```\n\n##### Examples\n\n```common-lisp\n(asdf:load-system \"flexi-streams\")\n; =\u003e NIL\n\n(flexi-streams:with-input-from-sequence (stream #(1 2 3))\n  (kee:loop for i being the bytes in stream\n            do (format t \"~w~%\" i)))\n; 1\n; 2\n; 3\n; =\u003e NIL\n```\n\n#### CHARACTERS Being Clause\n\nThe CHARACTERS being clause iterates over an input stream using\nREAD-CHAR. It terminates on EOF.\n\n```\npath-name        ::= {CHARACTER | CHARACTERS}\npreposition-name ::= {IN | OF | CLOSE}\nusing-name       ::= {STREAM}\n```\n\n##### Examples\n\n```common-lisp\n(with-input-from-string (stream \"abcd\")\n  (kee:loop for i being the characters in stream\n            do (format t \"~w~%\" i)))\n; #\\a\n; #\\b\n; #\\c\n; #\\d\n; =\u003e NIL\n```\n\n#### LINES Being Clause\n\nThe LINES being clause iterates over an input stream using\nREAD-LINE. It terminates on EOF.\n\n```\npath-name        ::= {LINE | LINES}\npreposition-name ::= {IN | OF | CLOSE}\nusing-name       ::= {STREAM | MISSING-NEWLINE-P}\n```\n\nIn addition to the standard stream prepositions and USING phrases it\nalso has the MISSING-NEWLINE-P USING phrase. This phrase is optional\nand specifies the name of variable to store the second value returned\nfrom READ-LINE which is non-NIL if the line was not terminated by a\nnewline.\n\n##### Examples\n\n```common-lisp\n(with-input-from-string (stream \"ab\nc\nd\")\n  (kee:loop for i being the lines in stream\n              using (missing-newline-p j)\n            do (format t \"~w ~w~%\" i j)))\n; \"ab\" NIL\n; \"c\" NIL\n; \"d\" T\n; =\u003e NIL\n```\n\n#### OBJECTS Being Clause\n\nThe OBJECTS being clause iterates over an input stream using\nREAD. It terminates on EOF.\n\n```\npath-name        ::= {OBJECT | OBJECTS}\npreposition-name ::= {IN | OF | CLOSE}\nusing-name       ::= {STREAM}\n```\n\n##### Examples\n\n```common-lisp\n(with-input-from-string (stream \"a 233d0 #C(1 2) (wibble)\")\n  (kee:loop for i being the objects in stream\n            do (format t \"~w~%\" i)))\n; A\n; 233.0d0\n; #C(1 2)\n; (WIBBLE)\n; =\u003e NIL\n```\n\n### Cons Iteration\n\n#### CARS Being Clause\n\nThe CARS being clause behaves the same as FOR-AS-IN-LIST, but is\nincluded to mirror the naming of MAPCAR and MAPLIST.\n\n```\npath-name        ::= {CAR | CARS}\npreposition-name ::= {IN | OF | BY}\nusing-name       ::= {}\n```\n\n##### Examples\n\n```common-lisp\n(kee:loop for i being the cars of '(1 2 3 4)\n          do (format t \"~w~%\" i))\n; 1\n; 2\n; 3\n; 4\n; =\u003e NIL\n\n(kee:loop for i being each car in '(1 2 3 4) by #'cddr\n          do (format t \"~w~%\" i))\n; 1\n; 3\n; =\u003e NIL\n```\n\n#### LISTS Being Clause\n\nThe LISTS being clause behaves the same as FOR-AS-ON-LIST, but is\nincluded to mirror the naming of MAPCAR and MAPLIST.\n\n```\npath-name        ::= {LIST | LISTS}\npreposition-name ::= {IN | OF | BY}\nusing-name       ::= {}\n```\n\n##### Examples\n\n```common-lisp\n(kee:loop for i being the lists of '(1 2 3 4)\n          do (format t \"~w~%\" i))\n; (1 2 3 4)\n; (2 3 4)\n; (3 4)\n; (4)\n; =\u003e NIL\n\n(kee:loop for i being each list in '(1 2 3 4) by #'cddr\n          do (format t \"~w~%\" i))\n; (1 2 3 4)\n; (3 4)\n; =\u003e NIL\n```\n\n### Permutation Iteration\n\n#### PERMUTATIONS Being Clause\n\nThe PERMUTATIONS being clause iterates over the permutations of a\nsequence.\n\n```\npath-name        ::= {PERMUTATION | PERMUTATIONS}\npreposition-name ::= {IN | OF}\nusing-name       ::= {}\n```\n\n* The IN and OF prepositions are a sequence to permute. On each loop\n  step a copy of this sequence is made with the elements permuted.\n\n##### Examples\n\n```common-lisp\n(kee:loop for p being the permutations of '(1 2 3)\n          collect p)\n; =\u003e ((1 2 3) (2 1 3) (3 1 2) (1 3 2) (2 3 1) (3 2 1))\n\n(kee:loop for p being each permutation of \"abc\"\n          collect p)\n; =\u003e (\"abc\" \"bac\" \"cab\" \"acb\" \"bca\" \"cba\")\n\n(kee:loop for p of-type list being each permutation of \"abc\"\n          collect p)\n; =\u003e ((#\\a #\\b #\\c) (#\\b #\\a #\\c) (#\\c #\\a #\\b) (#\\a #\\c #\\b) (#\\b #\\c #\\a)\n;     (#\\c #\\b #\\a))\n```\n\n#### COMBINATIONS Being Clause\n\nThe COMBINATIONS being clause iterates over the combinations of a\nsequence.\n\n```\npath-name        ::= {COMBINATION | COMBINATIONS}\npreposition-name ::= {IN | OF | CHOOSE}\nusing-name       ::= {}\n```\n\n* The IN and OF prepositions are a sequence to permute. On each loop\n  step a copy of this sequence is made with the elements permuted.\n* The CHOOSE prepositions is an integer that specifies the length of\n  the subsequence to select.\n\n##### Examples\n\n```common-lisp\n(kee:loop for c being each combination of '(1 2 3) choose 2\n          collect c)\n; =\u003e ((1 2) (1 3) (2 3))\n\n(kee:loop for c being the combinations of \"abc\" choose 2\n          collect c)\n; =\u003e (\"ab\" \"ac\" \"bc\")\n\n(kee:loop for c of-type list being each combination of \"abc\" choose 2\n          collect c)\n; =\u003e ((#\\a #\\b) (#\\a #\\c) (#\\b #\\c))\n```\n\n#### MULTICOMBINATIONS Being Clause\n\nThe MULTICOMBINATIONS being clause iterates over the combinations of a\nsequence with repetition allowed.\n\n```\npath-name        ::= {MULTICOMBINATION | MULTICOMBINATIONS}\npreposition-name ::= {IN | OF | CHOOSE}\nusing-name       ::= {}\n```\n\n* The IN and OF prepositions are a sequence to permute. On each loop\n  step a copy of this sequence is made with the elements permuted.\n* The CHOOSE prepositions is an integer that specifies the length of\n  the subsequence to select.\n\n##### Examples\n\n```common-lisp\n(kee:loop for c being each multicombination of '(1 2 3) choose 2\n          collect c)\n; =\u003e ((1 1) (1 2) (1 3) (2 2) (2 3))\n\n(kee:loop for c being the multicombinations of \"abc\" choose 2\n          collect c)\n; =\u003e (\"aa\" \"ab\" \"ac\" \"bb\" \"bc\")\n\n(kee:loop for c of-type list being each multicombination of \"abc\"\n            choose 2\n          collect c)\n; =\u003e ((#\\a #\\a) (#\\a #\\b) (#\\a #\\c) (#\\b #\\b) (#\\b #\\c))\n```\n\n#### TUPLES Being Clause\n\nThe TUPLES being clause iterates over the all possible tuples of a\ncollection of sequences. It is essentially the Cartesian Product.\n\n```\npath-name        ::= {TUPLE | TUPLES}\npreposition-name ::= {IN | OF}\nusing-name       ::= {}\n```\n\n* The IN and OF prepositions are a sequence of sequences. Instead of\n  individual sequences non-negative integers are also permitted which\n  imply a sequence of that length with integers less than the length.\n\n##### Examples\n\n```common-lisp\n(kee:loop for c being each tuple of '(\"abc\" (d e) 2)\n          collect c)\n; =\u003e ((#\\a D 0) (#\\a D 1) (#\\a E 0) (#\\a E 1) (#\\b D 0) (#\\b D 1) (#\\b E 0)\n;     (#\\b E 1) (#\\c D 0) (#\\c D 1) (#\\c E 0) (#\\c E 1))\n\n(kee:loop for c being the tuples of '(\"abc\" \"de\")\n          collect c)\n; =\u003e ((#\\a #\\d) (#\\a #\\e) (#\\b #\\d) (#\\b #\\e) (#\\c #\\d) (#\\c #\\e))\n\n(kee:loop for c of-type string being the tuples of '(\"abc\" \"de\")\n          collect c)\n; =\u003e (\"ad\" \"ae\" \"bd\" \"be\" \"cd\" \"ce\")\n```\n\n### Value Accumulation\n\n#### COLLECT/APPEND/NCONC Sequence Extensions\n\nThe value accumulation clauses COLLECT, COLLECTING, APPEND, APPENDING,\nNCONC, and NCONCING have all been extended to include type\nspecifications for arbitrary sequences.\n\n```common-lisp\n(kee:loop for i below 10\n          collect i of-type (vector fixnum))\n; =\u003e #(0 1 2 3 4 5 6 7 8 9)\n\n(kee:loop for i below 10\n          append (list i (- i)) of-type simple-vector)\n; =\u003e #(0 0 1 -1 2 -2 3 -3 4 -4 5 -5 6 -6 7 -7 8 -8 9 -9)\n\n(kee:loop for i from 65 to 90\n          collect (code-char i) of-type string)\n; =\u003e \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n```\n\n#### Set Accumulation\n\nThe set accumulation clauses ADJOIN, ADJOINING, DISJOIN, DISJOINING,\nUNION, UNIONING, NUNIONING, INTERSECTION, INTERSECTING, NINTERSECTION,\nNINSTERSECTING, DIFFERENCE, NDIFFERENCE, DIFFERENCING, and\nNDIFFERENCING have been added.\n\nAll of these accumulation clauses allow the optional prepositions KEY\nand TEST as in the :KEY and :TEST keyword arguments to CL:ADJOIN.\n\n```common-lisp\n(kee:loop for ch across \"The quick brown fox jumps over the lazy dog.\"\n          when (alpha-char-p ch)\n            adjoin ch test #'char-equal)\n; =\u003e (#\\T #\\h #\\e #\\q #\\u #\\i #\\c #\\k #\\b #\\r #\\o #\\w #\\n #\\f #\\x #\\j #\\m #\\p\n;     #\\s #\\v #\\l #\\a #\\z #\\y #\\d #\\g)\n\n(kee:loop for ch across \"The quick brown fox jumps over the lazy dog.\"\n          when (alpha-char-p ch)\n            adjoin ch of-type string test #'char-equal)\n; =\u003e \"Thequickbrownfxjmpsvlazydg\"\n\n(kee:loop for i below 10\n          union (list (mod i 3) (mod i 5)))\n; =\u003e (0 1 2 3 4)\n```\n\n#### Merge Accumulation\n\nA MERGE/MERGING accumulation clause has been added that uses\nCL:MERGE. It has a required preposition of PREDICATE and an optional\nKEY preposition.\n\n```common-lisp\n(kee:loop for i below 10\n          merge (list (- i) i) of-type vector predicate #'\u003c)\n; =\u003e #(-9 -8 -7 -6 -5 -4 -3 -2 -1 0 0 1 2 3 4 5 6 7 8 9)\n```\n\n### Subform Accumulation\n\nThe USE binding clause enables the use of value accumulation in subforms\nnested inside of LOOP. The syntax is:\n\n```\nuse-clause       ::= USE function-name = accumulation-name\n                     [INTO simple-var] [type-spec]\nfunction-name     ::= symbol\naccumulation-name ::= {ADJOIN | ADJOINING | APPEND | COLLECT |\n                       DIFFERENCE | DIFFERENCING | DISJOIN | \n                       DISJOINING | INTERSECTING | INTERSECTION | \n                       MERGE | NCONC | NDIFFERENCE | NDIFFERENCING |\n                       NINTERSECTING | NINTERSECTION | NUIONION | \n                       UNION | UNIONING}\n```\n\nA local function will then be created with \"function-name\" that takes\na single argument that will be accumulated, along with key arguments for\nany prepositions.\n\n```common-lisp\n(kee:loop use my-collect = collect\n          for i below 10\n          do (my-collect i))\n; =\u003e (0 1 2 3 4 5 6 7 8 9)\n\n(kee:loop use my-adjoin = adjoin\n          for ch across \"The quick brown fox jumps over the lazy dog.\"\n          when (alpha-char-p ch)\n            do (my-adjoin ch :test #'char-equal))\n; =\u003e (#\\T #\\h #\\e #\\q #\\u #\\i #\\c #\\k #\\b #\\r #\\o #\\w #\\n #\\f #\\x #\\j #\\m\n;     #\\p #\\s #\\v #\\l #\\a #\\z #\\y #\\d #\\g)\n\n(kee:loop use my-max = maximize into q\n          for i from 1 upto 10\n          finally (return q)\n          do (my-max (random i)))\n; =\u003e 7\n```\n\n### CLEANUP Clause\n\nThe FINALLY clause of CL:LOOP is not guaranteed to be executed and\ntherefore is not a good place to put cleanup forms from bindings\nintroduced by WITH clauses. khazern-extension has the CLEANUP clause\nfor this. It has identical syntax as the FINALLY clause, but it places\nits forms inside an UNWIND-PROTECT.\n\n```common-lisp\n(macroexpand-1 '(kee:loop with x = (make-fubar)\n                          cleanup (release-fubar x)))\n; =\u003e (BLOCK NIL\n;      (LET ((X NIL) (#:FORM229 (MAKE-FUBAR)))\n;        (DECLARE (IGNORABLE X))\n;        (SETQ X #:FORM229)\n;        (UNWIND-PROTECT\n;            (TAGBODY\n;             #:BODY230\n;              (GO #:BODY230)\n;             KHAZERN-EXTENSION-EXTRINSIC::EPILOGUE\n;              (RETURN-FROM NIL NIL))\n;          (RELEASE-FUBAR X)))),\n;    T\n```\n\n[Quicklisp]: https://www.quicklisp.org/beta/\n[SICL]: https://github.com/robert-strandh/SICL\n[Ultralisp]: https://ultralisp.org/\n[ocicl]: https://github.com/ocicl/ocicl","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fs-expressionists%2Fkhazern","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fs-expressionists%2Fkhazern","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fs-expressionists%2Fkhazern/lists"}