项目作者: obfusk

项目描述 :
koneko - a concatenative not-quite-lisp for kittens
高级语言: Haskell
项目地址: git://github.com/obfusk/koneko.git
创建时间: 2017-11-18T07:42:20Z
项目社区:https://github.com/obfusk/koneko

开源协议:GNU General Public License v3.0

下载


GitHub Release
Hackage
npm
CI
GPLv3+
LGPLv3+
!-- [![Sponsor](https://img.shields.io/badge/%E2%99%A5-support-violet.svg)](https://ko-fi.com/obfusk) --


koneko logo

koneko - a concatenative not-quite-lisp for kittens

Description,
Whirlwind Tour,
Language Reference,
More Examples,
Doctests;


Installing,
Running,
(Build) Requirements,
Specs & Docs,
Vim Syntax Highlighting;


TODO,
License

Description

NB: work in progress.

Koneko (子猫 — “kitten” in Japanese) is a simple functional
concatenative stack-based programming language with Lisp (& Haskell)
influences. It is intended to combine the elegance of the
(point-free) “concatenation is composition” model with the elegance of
Lisp-like languages.

→ Try koneko in your browser with the JavaScript
REPL.

Properties

  • concatenative
    • point-free
    • juxtaposition of expressions denotes function composition
  • stack-oriented
    • postfix (reverse polish) notation
    • functions consume arguments from the stack
    • functions produce return values on the stack
  • Lisp-like
    • homoiconic
    • blocks (anonymous functions, similar to lambdas)
    • named parameters/points (lexically scoped)
  • functional
    • only immutable data structures
    • does have side effects (I/O)
    • (mostly) strict evaluation
  • dynamically, strongly typed

Features

  • primitive (built-in):
    • primitive data types: nil, bool, int, float, str, kwd
    • composite data types: pair, list, dict
    • multi(method)s (similar to multiple dispatch & type classes)
    • records (similar to algebraic data types)
    • modules
    • regexes (mostly Perl-compatible and thus not actually “regular” expressions)
    • concurrency (& parallelism)
    • exception handling
    • thunks
  • prelude (standard library):
    • stack shuffling
    • combinators (stack-oriented higher-order functions)
    • arithmetic
    • string operations
    • ranges, lazy sequences & sequence operations
    • slicing & associative structure operations
    • looping & basic I/O
    • either, functor, monad
  • nil punning
  • syntactic sugar (on top of a minimal “core language”)

Whirlwind Tour

Hello World

  1. $ koneko -e '"Hello, World!" say!'
  2. hello, World!

REPL

  1. $ koneko
  2. >>> "Hello, World!" say!
  3. Hello, World!
  4. >>> ^D

The Weird (& Wonderful)

  1. >>> 1 2 + ; postfix notation
  2. 3
  3. >>> drop ; functions manipulate the stack
  4. >>> ( 3 4 ) ; literals push a value onto the stack
  5. ( 3 4 )
  6. >>> len dup ; unquoted identifiers are calls
  7. 2
  8. >>> '+ ; quoted identifiers push themselves
  9. #<multi:2:+>
  10. >>> call ; and can then be called explicitly
  11. 4
  12. >>> ( 1 2 3 )
  13. ( 1 2 3 )
  14. >>> reverse show ; concatenation is function composition
  15. "( 3 2 1 )"
  16. >>> ( 4 5, 6 ) ; commas are whitespace
  17. ( 4 5 6 )
  18. ; unless a line starts with a comma, the command-line repl will print
  19. ; the top of the stack after evaluating it
  20. >>> , 7 2
  21. >>> -
  22. 5
  23. >>> ,s! ; show the stack (non-browser repl only)
  24. --- STACK ---
  25. 5
  26. ( 4 5 6 )
  27. "( 3 2 1 )"
  28. 4
  29. --- END ---
  30. >>> clear-stack! ; clear the stack (repl only)
  31. *** STACK CLEARED ***

NB: use whitespace to separate tokens since “special” characters like
+ and ( are not delimiters but valid parts of identifiers.

  1. >>> 1 2+
  2. *** ERROR: name 2+ is not defined
  3. >>> (1 2)
  4. *** ERROR: name (1 is not defined

Details:
Language Features,
Ident(ifiers) & Quoting

Data Types

NB: all data types are immutable.

  1. >>> () ; empty list
  2. ()
  3. >>> ( nil #t #f ) ; list containing nil, true & false
  4. ( nil #t #f )
  5. >>> ( 1 2 + 4 ) ; nested expressions are evaluated
  6. ( 3 4 )
  7. >>> 32 0x20 0b100000 ; integers
  8. 32
  9. >>> 3.14 ; floating point
  10. 3.14
  11. >>> "spam & eggs" ; string
  12. "spam & eggs"
  13. >>> :foo ; keyword (aka symbol)
  14. :foo
  15. >>> :answer 42 => ; key/value pair
  16. :answer 42 =>
  17. >>> { x: 42, :y 99 1 + => } ; dict: key/value map
  18. { :x 42 =>, :y 100 => }

NB: nil and #f are falsy, everything else is truthy.

  1. >>> , :Point ( :x :y ) defrecord ; define record type
  2. >>> Point( 1 -1 ) ; "list" constructor
  3. Point{ :x 1 =>, :y -1 => }
  4. >>> Point{ y: -1, x: 1 } ; "dict" constructor
  5. Point{ :x 1 =>, :y -1 => }
  6. >>> .x ; field access
  7. 1

Details:
Primitive Data Types,
Pairs, Lists & Dicts,
Records

Functions

  1. >>> , 2 7 ; push 2 and 7
  2. >>> [ swap - ] ; push a block
  3. [ swap - ]
  4. >>> call ; call the block
  5. 5
  6. >>> , :swap-and-subtract [ swap - ] def ; named block
  7. >>> 2 7 swap-and-subtract
  8. 5

NB: since purely concatenative programs contain no free variables,
almost any “subexpression” can be “factored out” simply by giving it a
name.

  1. >>> , :myswap [ x y . 'y 'x ] def ; named parameters
  2. >>> , 1 2 myswap s!
  3. --- STACK ---
  4. 1
  5. 2
  6. --- END ---
  7. >>> 1 2 [ x y . y x ] call ; remember to quote non-calls
  8. *** ERROR: type int is not callable
  9. >>> [1 +] ; remember to use whitespace
  10. *** ERROR: name [1 is not defined

Details:
Functions,
Multi(method)s

Primitives & Prelude

Details:
Primitives, Builtins & Prelude,
Prelude: Syntax Highlighted Source,
Prelude: Function Index

  1. >>> , :inc [ 1 + ] def ; naming things
  2. >>> 41 'inc call ; explicit call
  3. 42
  4. >>> 1 2 < ; comparison: = not= < <= > >=
  5. #t
  6. >>> [ :less ] [ :not-less ] if ; conditional
  7. :less
  8. >>> ( 42 ) show ; convert to readable str
  9. "( 42 )"
  10. >>> "foo" show
  11. "\"foo\""
  12. >>> , "Hello!" say! ; print line
  13. Hello!

Stack Shuffling

  1. >>> 1 2 swap drop dup + ; swap, drop the 1, dup the 2, add
  2. 4

Combinators

  1. >>> , 35 [ 2 + ] [ 7 + ] bi ; call two functions on 1 value
  2. >>> , s!
  3. --- STACK ---
  4. 42
  5. 37
  6. --- END ---

Syntactic Sugar

  1. >>> answer: 42 ; pair w/ single-token value
  2. :answer 42 =>
  3. >>> { x: 1, y: 2 } ; dict literal
  4. { :x 1 =>, :y 2 => }
  5. >>> 1 ( 2 3 ) !cons ; field call (field access + call)
  6. ( 1 2 3 )
  7. >>> '.x ; quoted field access
  8. [ :x __swap__ __call__ ]
  9. >>> '!x ; quoted field call
  10. [ :x __swap__ __call__ __call__ ]
  11. >>> '[ 2 * '1 div ] ; "curried" block w/ "holes"
  12. [ __1__ . [ 2 * '__1__ div ] ]
  13. >>> 3 swap call ; "fill" the hole from the stack
  14. [ 2 * '__1__ div ]
  15. >>> 5 swap call
  16. 3

Details:
Syntactic Sugar

Examples

  1. >>> , :fibs ( 0 1 ) [ 'fibs dup rest '+ zip ] lseq def
  2. >>> 'fibs 10 take-first ->list
  3. ( 0 1 1 2 3 5 8 13 21 34 )
  4. >>> 'fibs 10 nth
  5. 55
  1. >>> "" 0.0 0.0 / show .[ '1 ++ ] 10 times " batman!" ++ say!
  2. NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN batman!
  1. >>> 15 [1-n] [ dup 3 "fizz" 5 "buzz" '[ '1 div? '2 "" ? ] 2bi$ bi
  2. ... ++ 'show 'nip ~seq say! ] each
  3. 1
  4. 2
  5. fizz
  6. 4
  7. buzz
  8. fizz
  9. 7
  10. 8
  11. fizz
  12. buzz
  13. 11
  14. fizz
  15. 13
  16. 14
  17. fizzbuzz

Language Reference

01: Language Features,


02: Ident(ifiers) & Quoting,


03: Primitive Data Types,


04: Pairs, Lists & Dicts,


05: Functions,


06: Multi(method)s,


07: Records,


08: Syntactic Sugar,


09: Primitives, Builtins & Prelude,


10: Standard Library,


11: Possible Future Extensions

Prelude

Syntax Highlighted Source,
Function Index

More Examples

More Examples

Doctests

Like Python (& Haskell), koneko supports “doctests”: executable pieces
of documentation that look like interactive REPL sessions. Doctests
make it easy to write user tutorials, documentation, and regression
tests at the same time and confirm that examples in documentation are
correct and up to date.

NB: this README, the Language Reference, and koneko’s Prelude &
Standard Library are full of doctests.

Lets look at an example, mylib.knk:

  1. :mylib defmodule[
  2. ; swap top 2 values
  3. ;
  4. ; >>> :mylib use
  5. ; >>> , 1 2 s!
  6. ; --- STACK ---
  7. ; 2
  8. ; 1
  9. ; --- END ---
  10. ; >>> , myswap s!
  11. ; --- STACK ---
  12. ; 1
  13. ; 2
  14. ; --- END ---
  15. :myswap [ x y . 'y 'x ] def
  16. ] ; defmodule

We run koneko with the --doctest option (in this case also with -v
for verbosity) to execute the tests in a koneko — or markdown —
file:

  1. $ KONEKOPATH=. koneko --doctest -v mylib.knk
  2. === Testing mylib.knk (koneko) ===
  3. Trying:
  4. :mylib use
  5. Expecting:
  6. ok
  7. Trying:
  8. , 1 2 s!
  9. Expecting:
  10. --- STACK ---
  11. 2
  12. 1
  13. --- END ---
  14. ok
  15. Trying:
  16. , myswap s!
  17. Expecting:
  18. --- STACK ---
  19. 1
  20. 2
  21. --- END ---
  22. ok
  23. Total: 3, Tried: 3, Passed: 3, Failed: 0.
  24. === Summary ===
  25. Total: 3, Tried: 3, Passed: 3, Failed: 0.
  26. Test passed.
  27. === Summary ===
  28. Files: 1.
  29. Total: 3, Tried: 3, Passed: 3, Failed: 0.
  30. Test passed.

NB: for :mylib use to be able to load the mylib.knk file we need
to add the current directory to KONEKOPATH.

Installing

See (Build) Requirements.

… TODO …

Running

Linux (& Probably macOS and *BSD)

  1. $ make cabal_build # Haskell Build
  2. $ ./scripts/repl_hs # Haskell REPL
  3. $ ./scripts/repl_js # Node.js REPL
  4. $ make repl_browser # Browser REPL

Windows (Untested)

  1. $ cabal v2-build --write-ghc-environment-files=always --enable-tests
  2. $ cabal v2-run koneko # Haskell REPL
  3. $ node js\koneko # Node.js REPL

… TODO …

(Build) Requirements

The Haskell implementation requires GHC,
cabal-install (and a few additional libraries
that can be installed using Cabal); see koneko.cabal for the dependencies.

The JavaScript implementation requires Node.js.

Debian

  1. $ apt install cabal-install libghc-aeson-dev libghc-async-dev \
  2. libghc-cmdargs-dev libghc-doctest-dev libghc-hashtables-dev \
  3. libghc-megaparsec-dev libghc-random-dev libghc-regex-pcre-dev \
  4. libghc-safe-dev libghc-silently-dev libghc-split-dev \
  5. libghc-unordered-containers-dev libghc-vector-dev # Haskell version
  6. $ apt install nodejs # Node.js version
  7. $ apt install rlwrap # (readline support)

Specs & Docs

  1. $ make cabal_build test_haskell # Haskell
  2. $ make test_node # JavaScript

TODO: haddock

Vim Syntax Highlighting

  1. $ make link_vim_syntax # symlinks misc/vim/ files from ~/.vim
  2. $ make copy_vim_syntax # copies misc/vim/ files to ~/.vim

TODO

  • finish design
  • finish documentation
  • finish implementation
  • ???
  • profit!

License

Interpreter(s)

GPLv3+

Standard Library

(i.e. lib/*.knk)

LGPLv3+