{"id":17160198,"url":"https://github.com/obfusk/koneko","last_synced_at":"2025-04-11T12:10:46.099Z","repository":{"id":56845204,"uuid":"111186467","full_name":"obfusk/koneko","owner":"obfusk","description":"koneko - a concatenative not-quite-lisp for kittens","archived":false,"fork":false,"pushed_at":"2024-08-30T02:07:58.000Z","size":1270,"stargazers_count":23,"open_issues_count":34,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-25T08:37:44.374Z","etag":null,"topics":["concatenative","functional-programming","language","lisp","programming-language","stack","work-in-progress"],"latest_commit_sha":null,"homepage":"https://koneko.dev","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/obfusk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.GPLv3","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":"2017-11-18T07:42:20.000Z","updated_at":"2025-01-06T07:28:01.000Z","dependencies_parsed_at":"2024-08-29T01:26:35.951Z","dependency_job_id":"3e43dc6a-1555-4872-b283-29f8e3f831a3","html_url":"https://github.com/obfusk/koneko","commit_stats":{"total_commits":366,"total_committers":1,"mean_commits":366.0,"dds":0.0,"last_synced_commit":"3bb62aae7a8ee0d21136c18f7fe5e6cff9676a30"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/obfusk%2Fkoneko","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/obfusk%2Fkoneko/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/obfusk%2Fkoneko/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/obfusk%2Fkoneko/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/obfusk","download_url":"https://codeload.github.com/obfusk/koneko/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247888556,"owners_count":21013001,"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":["concatenative","functional-programming","language","lisp","programming-language","stack","work-in-progress"],"created_at":"2024-10-14T22:24:01.909Z","updated_at":"2025-04-11T12:10:46.076Z","avatar_url":"https://github.com/obfusk.png","language":"Haskell","funding_links":["https://ko-fi.com/obfusk"],"categories":[],"sub_categories":[],"readme":"\u003c!-- SPDX-FileCopyrightText: 2024 FC (Fay) Stegerman \u003cflx@obfusk.net\u003e --\u003e\n\u003c!-- SPDX-License-Identifier: GPL-3.0-or-later --\u003e\n\n\u003c!-- TODO: badges --\u003e\n\n[![GitHub Release](https://img.shields.io/github/release/obfusk/koneko.svg?logo=github)](https://github.com/obfusk/koneko/releases)\n[![Hackage](https://img.shields.io/hackage/v/koneko)](https://hackage.haskell.org/package/koneko)\n[![npm](https://img.shields.io/npm/v/koneko)](https://www.npmjs.com/package/koneko)\n[![CI](https://github.com/obfusk/koneko/workflows/CI/badge.svg)](https://github.com/obfusk/koneko/actions?query=workflow%3ACI)\n[![GPLv3+](https://img.shields.io/badge/license-GPLv3+-blue.svg)](https://www.gnu.org/licenses/gpl-3.0.html)\n[![LGPLv3+](https://img.shields.io/badge/license-LGPLv3+-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0.html)\n\u003c!--\n[![Sponsor](https://img.shields.io/badge/%E2%99%A5-support-violet.svg)](https://ko-fi.com/obfusk)\n--\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"logo.svg\" alt=\"koneko logo\" width=\"150\" /\u003e\u003cbr /\u003e\n  koneko - a concatenative not-quite-lisp for kittens\n\u003c/p\u003e\n\n→ [Description](#description),\n→ [Whirlwind Tour](#whirlwind-tour),\n→ [Language Reference](#language-reference),\n→ [More Examples](#more-examples),\n→ [Doctests](#doctests);\n\u003cbr/\u003e\n→ [Installing](#installing),\n→ [Running](#running),\n→ [(Build) Requirements](#build-requirements),\n→ [Specs \u0026 Docs](#specs--docs),\n→ [Vim Syntax Highlighting](#vim-syntax-highlighting);\n\u003cbr/\u003e\n→ [TODO](#todo),\n→ [License](#license)\n\n## Description\n\n**NB: work in progress.**\n\nKoneko (子猫 -- \"kitten\" in Japanese) is a simple functional\nconcatenative stack-based programming language with Lisp (\u0026 Haskell)\ninfluences.  It is intended to combine the elegance of the\n(point-free) \"concatenation is composition\" model with the elegance of\nLisp-like languages.\n\n**→ Try koneko in your browser with the JavaScript\n[REPL](https://koneko.dev).**\n\n### Properties\n\n* concatenative\n  - point-free\n  - juxtaposition of expressions denotes function composition\n* stack-oriented\n  - postfix (reverse polish) notation\n  - functions consume arguments from the stack\n  - functions produce return values on the stack\n* Lisp-like\n  - homoiconic\n  - blocks (anonymous functions, similar to lambdas)\n  - named parameters/points (lexically scoped)\n* functional\n  - only immutable data structures\n  - does have side effects (I/O)\n  - (mostly) strict evaluation\n* dynamically, strongly typed\n\n### Features\n\n* primitive (built-in):\n  - primitive data types: nil, bool, int, float, str, kwd\n  - composite data types: pair, list, dict\n  - multi(method)s (similar to multiple dispatch \u0026 type classes)\n  - records (similar to algebraic data types)\n  - modules\n  - regexes (mostly Perl-compatible and thus not actually \"regular\" expressions)\n  - concurrency (\u0026 parallelism)\n  - exception handling\n  - thunks\n* prelude (standard library):\n  - stack shuffling\n  - combinators (stack-oriented higher-order functions)\n  - arithmetic\n  - string operations\n  - ranges, lazy sequences \u0026 sequence operations\n  - slicing \u0026 associative structure operations\n  - looping \u0026 basic I/O\n  - either, functor, monad\n* nil punning\n* syntactic sugar (on top of a minimal \"core language\")\n\n## Whirlwind Tour\n\n### Hello World\n\n```bash\n$ koneko -e '\"Hello, World!\" say!'\nhello, World!\n```\n\n### REPL\n\n```bash\n$ koneko\n\u003e\u003e\u003e \"Hello, World!\" say!\nHello, World!\n\u003e\u003e\u003e ^D\n```\n\n### The Weird (\u0026 Wonderful)\n\n```koneko\n\u003e\u003e\u003e 1 2 +                     ; postfix notation\n3\n\n\u003e\u003e\u003e drop                      ; functions manipulate the stack\n\u003e\u003e\u003e ( 3 4 )                   ; literals push a value onto the stack\n( 3 4 )\n\n\u003e\u003e\u003e len dup                   ; unquoted identifiers are calls\n2\n\u003e\u003e\u003e '+                        ; quoted identifiers push themselves\n#\u003cmulti:2:+\u003e\n\u003e\u003e\u003e call                      ; and can then be called explicitly\n4\n\n\u003e\u003e\u003e ( 1 2 3 )\n( 1 2 3 )\n\u003e\u003e\u003e reverse show              ; concatenation is function composition\n\"( 3 2 1 )\"\n\n\u003e\u003e\u003e ( 4 5, 6 )                ; commas are whitespace\n( 4 5 6 )\n\n; unless a line starts with a comma, the command-line repl will print\n; the top of the stack after evaluating it\n\u003e\u003e\u003e , 7 2\n\u003e\u003e\u003e -\n5\n\n\u003e\u003e\u003e ,s!                       ; show the stack (non-browser repl only)\n--- STACK ---\n5\n( 4 5 6 )\n\"( 3 2 1 )\"\n4\n---  END  ---\n\u003e\u003e\u003e clear-stack!              ; clear the stack (repl only)\n*** STACK CLEARED ***\n```\n\nNB: use whitespace to separate tokens since \"special\" characters like\n`+` and `(` are not delimiters but valid parts of identifiers.\n\n```koneko\n\u003e\u003e\u003e 1 2+\n*** ERROR: name 2+ is not defined\n\u003e\u003e\u003e (1 2)\n*** ERROR: name (1 is not defined\n```\n\nDetails:\n→ [Language Features](doc/01-language-features.md),\n→ [Ident(ifiers) \u0026 Quoting](doc/02-identifiers-and-quoting.md)\n\n### Data Types\n\nNB: all data types are immutable.\n\n```koneko\n\u003e\u003e\u003e ()                            ; empty list\n()\n\u003e\u003e\u003e ( nil #t #f )                 ; list containing nil, true \u0026 false\n( nil #t #f )\n\u003e\u003e\u003e ( 1 2 + 4 )                   ; nested expressions are evaluated\n( 3 4 )\n\n\u003e\u003e\u003e 32 0x20 0b100000              ; integers\n32\n\u003e\u003e\u003e 3.14                          ; floating point\n3.14\n\n\u003e\u003e\u003e \"spam \u0026 eggs\"                 ; string\n\"spam \u0026 eggs\"\n\u003e\u003e\u003e :foo                          ; keyword (aka symbol)\n:foo\n\n\u003e\u003e\u003e :answer 42 =\u003e                 ; key/value pair\n:answer 42 =\u003e\n\u003e\u003e\u003e { x: 42, :y 99 1 + =\u003e }       ; dict: key/value map\n{ :x 42 =\u003e, :y 100 =\u003e }\n```\n\nNB: `nil` and `#f` are falsy, everything else is truthy.\n\n```koneko\n\u003e\u003e\u003e , :Point ( :x :y ) defrecord  ; define record type\n\u003e\u003e\u003e Point( 1 -1 )                 ; \"list\" constructor\nPoint{ :x 1 =\u003e, :y -1 =\u003e }\n\u003e\u003e\u003e Point{ y: -1, x: 1 }          ; \"dict\" constructor\nPoint{ :x 1 =\u003e, :y -1 =\u003e }\n\u003e\u003e\u003e .x                            ; field access\n1\n```\n\nDetails:\n→ [Primitive Data Types](doc/03-primitive-data-types.md),\n→ [Pairs, Lists \u0026 Dicts](doc/04-pairs-lists-and-dicts.md),\n→ [Records](doc/07-records.md)\n\n### Functions\n\n```koneko\n\u003e\u003e\u003e , 2 7                                 ; push 2 and 7\n\u003e\u003e\u003e [ swap - ]                            ; push a block\n[ swap - ]\n\u003e\u003e\u003e call                                  ; call the block\n5\n\u003e\u003e\u003e , :swap-and-subtract [ swap - ] def   ; named block\n\u003e\u003e\u003e 2 7 swap-and-subtract\n5\n```\n\nNB: since purely concatenative programs contain no free variables,\nalmost any \"subexpression\" can be \"factored out\" simply by giving it a\nname.\n\n```koneko\n\u003e\u003e\u003e , :myswap [ x y . 'y 'x ] def         ; named parameters\n\u003e\u003e\u003e , 1 2 myswap s!\n--- STACK ---\n1\n2\n---  END  ---\n\n\u003e\u003e\u003e 1 2 [ x y . y x ] call                ; remember to quote non-calls\n*** ERROR: type int is not callable\n\u003e\u003e\u003e [1 +]                                 ; remember to use whitespace\n*** ERROR: name [1 is not defined\n```\n\nDetails:\n→ [Functions](doc/05-functions.md),\n→ [Multi(method)s](doc/06-multimethods.md)\n\n### Primitives \u0026 Prelude\n\nDetails:\n→ [Primitives, Builtins \u0026 Prelude](doc/09-primitives-builtins-and-prelude.md),\n→ [Prelude: Syntax Highlighted Source](https://koneko.dev/lib-doc/prelude.knk.html),\n→ [Prelude: Function Index](https://koneko.dev/lib-doc/prelude.knk.index.html)\n\n```koneko\n\u003e\u003e\u003e , :inc [ 1 + ] def          ; naming things\n\u003e\u003e\u003e 41 'inc call                ; explicit call\n42\n\n\u003e\u003e\u003e 1 2 \u003c                       ; comparison: = not= \u003c \u003c= \u003e \u003e=\n#t\n\u003e\u003e\u003e [ :less ] [ :not-less ] if  ; conditional\n:less\n\n\u003e\u003e\u003e ( 42 ) show                 ; convert to readable str\n\"( 42 )\"\n\u003e\u003e\u003e \"foo\" show\n\"\\\"foo\\\"\"\n\n\u003e\u003e\u003e , \"Hello!\" say!             ; print line\nHello!\n```\n\n#### Stack Shuffling\n\n```koneko\n\u003e\u003e\u003e 1 2 swap drop dup +         ; swap, drop the 1, dup the 2, add\n4\n```\n\n#### Combinators\n\n```koneko\n\u003e\u003e\u003e , 35 [ 2 + ] [ 7 + ] bi     ; call two functions on 1 value\n\u003e\u003e\u003e , s!\n--- STACK ---\n42\n37\n---  END  ---\n```\n\n### Syntactic Sugar\n\n```koneko\n\u003e\u003e\u003e answer: 42                      ; pair w/ single-token value\n:answer 42 =\u003e\n\u003e\u003e\u003e { x: 1, y: 2 }                  ; dict literal\n{ :x 1 =\u003e, :y 2 =\u003e }\n\n\u003e\u003e\u003e 1 ( 2 3 ) !cons                 ; field call (field access + call)\n( 1 2 3 )\n\n\u003e\u003e\u003e '.x                             ; quoted field access\n[ :x __swap__ __call__ ]\n\u003e\u003e\u003e '!x                             ; quoted field call\n[ :x __swap__ __call__ __call__ ]\n\n\u003e\u003e\u003e '[ 2 * '1 div ]                 ; \"curried\" block w/ \"holes\"\n[ __1__ . [ 2 * '__1__ div ] ]\n\u003e\u003e\u003e 3 swap call                     ; \"fill\" the hole from the stack\n[ 2 * '__1__ div ]\n\u003e\u003e\u003e 5 swap call\n3\n```\n\nDetails:\n→ [Syntactic Sugar](doc/08-syntactic-sugar.md)\n\n### Examples\n\n```koneko\n\u003e\u003e\u003e , :fibs ( 0 1 ) [ 'fibs dup rest '+ zip ] lseq def\n\u003e\u003e\u003e 'fibs 10 take-first -\u003elist\n( 0 1 1 2 3 5 8 13 21 34 )\n\u003e\u003e\u003e 'fibs 10 nth\n55\n```\n\n```koneko\n\u003e\u003e\u003e \"\" 0.0 0.0 / show .[ '1 ++ ] 10 times \" batman!\" ++ say!\nNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN batman!\n```\n\n```koneko\n\u003e\u003e\u003e 15 [1-n] [ dup 3 \"fizz\" 5 \"buzz\" '[ '1 div? '2 \"\" ? ] 2bi$ bi\n...            ++ 'show 'nip ~seq say! ] each\n1\n2\nfizz\n4\nbuzz\nfizz\n7\n8\nfizz\nbuzz\n11\nfizz\n13\n14\nfizzbuzz\n```\n\n## Language Reference\n\n→ [01: Language Features](doc/01-language-features.md),\n\u003cbr/\u003e\n→ [02: Ident(ifiers) \u0026 Quoting](doc/02-identifiers-and-quoting.md),\n\u003cbr/\u003e\n→ [03: Primitive Data Types](doc/03-primitive-data-types.md),\n\u003cbr/\u003e\n→ [04: Pairs, Lists \u0026 Dicts](doc/04-pairs-lists-and-dicts.md),\n\u003cbr/\u003e\n→ [05: Functions](doc/05-functions.md),\n\u003cbr/\u003e\n→ [06: Multi(method)s](doc/06-multimethods.md),\n\u003cbr/\u003e\n→ [07: Records](doc/07-records.md),\n\u003cbr/\u003e\n→ [08: Syntactic Sugar](doc/08-syntactic-sugar.md),\n\u003cbr/\u003e\n→ [09: Primitives, Builtins \u0026 Prelude](doc/09-primitives-builtins-and-prelude.md),\n\u003cbr/\u003e\n→ [10: Standard Library](doc/10-standard-library.md),\n\u003cbr/\u003e\n→ [11: Possible Future Extensions](doc/11-future.md)\n\n### Prelude\n\n→ [Syntax Highlighted Source](https://koneko.dev/lib-doc/prelude.knk.html),\n→ [Function Index](https://koneko.dev/lib-doc/prelude.knk.index.html)\n\n## More Examples\n\n→ [More Examples](doc/more-examples.md)\n\n## Doctests\n\nLike Python (\u0026 Haskell), koneko supports \"doctests\": executable pieces\nof documentation that look like interactive REPL sessions.  Doctests\nmake it easy to write user tutorials, documentation, and regression\ntests at the same time and confirm that examples in documentation are\ncorrect and up to date.\n\nNB: this README, the Language Reference, and koneko's Prelude \u0026\nStandard Library are full of doctests.\n\nLets look at an example, `mylib.knk`:\n\n```koneko\n:mylib defmodule[\n\n; swap top 2 values\n;\n; \u003e\u003e\u003e :mylib use\n; \u003e\u003e\u003e , 1 2 s!\n; --- STACK ---\n; 2\n; 1\n; ---  END  ---\n; \u003e\u003e\u003e , myswap s!\n; --- STACK ---\n; 1\n; 2\n; ---  END  ---\n\n:myswap [ x y . 'y 'x ] def\n\n] ; defmodule\n```\n\nWe run koneko with the `--doctest` option (in this case also with `-v`\nfor verbosity) to execute the tests in a koneko -- or markdown --\nfile:\n\n```bash\n$ KONEKOPATH=. koneko --doctest -v mylib.knk\n=== Testing mylib.knk (koneko) ===\nTrying:\n  :mylib use\nExpecting:\nok\nTrying:\n  , 1 2 s!\nExpecting:\n  --- STACK ---\n  2\n  1\n  ---  END  ---\nok\nTrying:\n  , myswap s!\nExpecting:\n  --- STACK ---\n  1\n  2\n  ---  END  ---\nok\nTotal: 3, Tried: 3, Passed: 3, Failed: 0.\n=== Summary ===\nTotal: 3, Tried: 3, Passed: 3, Failed: 0.\nTest passed.\n\n=== Summary ===\nFiles: 1.\nTotal: 3, Tried: 3, Passed: 3, Failed: 0.\nTest passed.\n```\n\nNB: for `:mylib use` to be able to load the `mylib.knk` file we need\nto add the current directory to `KONEKOPATH`.\n\n## Installing\n\nSee [(Build) Requirements](#build-requirements).\n\n... TODO ...\n\n## Running\n\n### Linux (\u0026 Probably macOS and *BSD)\n\n```bash\n$ make cabal_build                                      # Haskell Build\n$ ./scripts/repl_hs                                     # Haskell REPL\n\n$ ./scripts/repl_js                                     # Node.js REPL\n$ make repl_browser                                     # Browser REPL\n```\n\n### Windows (Untested)\n\n```\n$ cabal v2-build --write-ghc-environment-files=always --enable-tests\n$ cabal v2-run koneko                                   # Haskell REPL\n\n$ node js\\koneko                                        # Node.js REPL\n```\n\n... TODO ...\n\n## (Build) Requirements\n\nThe Haskell implementation requires [GHC](https://www.haskell.org/ghc/),\n[`cabal-install`](https://cabal.readthedocs.io/) (and a few additional libraries\nthat can be installed using Cabal); see `koneko.cabal` for the dependencies.\n\nThe JavaScript implementation requires Node.js.\n\n### Debian\n\n```bash\n$ apt install cabal-install libghc-aeson-dev libghc-async-dev \\\n  libghc-cmdargs-dev libghc-doctest-dev libghc-hashtables-dev \\\n  libghc-megaparsec-dev libghc-random-dev libghc-regex-pcre-dev \\\n  libghc-safe-dev libghc-silently-dev libghc-split-dev \\\n  libghc-unordered-containers-dev libghc-vector-dev     # Haskell version\n$ apt install nodejs                                    # Node.js version\n$ apt install rlwrap                                    # (readline support)\n```\n\n## Specs \u0026 Docs\n\n```bash\n$ make cabal_build test_haskell                         # Haskell\n$ make test_node                                        # JavaScript\n```\n\nTODO: haddock\n\n## Vim Syntax Highlighting\n\n```bash\n$ make link_vim_syntax    # symlinks misc/vim/ files from ~/.vim\n$ make copy_vim_syntax    # copies   misc/vim/ files to   ~/.vim\n```\n\n## TODO\n\n* finish design\n* finish documentation\n* finish implementation\n* ???\n* profit!\n\n## License\n\n### Interpreter(s)\n\n[![GPLv3+](https://www.gnu.org/graphics/gplv3-127x51.png)](https://www.gnu.org/licenses/gpl-3.0.html)\n\n### Standard Library\n\n(i.e. `lib/*.knk`)\n\n[![LGPLv3+](https://www.gnu.org/graphics/lgplv3-147x51.png)](https://www.gnu.org/licenses/lgpl-3.0.html)\n\n\u003c!-- vim: set tw=70 sw=2 sts=2 et fdm=marker : --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fobfusk%2Fkoneko","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fobfusk%2Fkoneko","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fobfusk%2Fkoneko/lists"}