A comprehensive implementation of the K programming language, version 3, a vector programming language from the APL family.
ksharp
Copyright (c) 2026 Eusebio Rufian-Zilbermann et al.
This software is licensed under the terms of the MIT License with Commons Clause.
You are free to use, modify, and distribute it (including in commercial products), provided you include attribution and do not sell the software (or a product whose value derives substantially from this software) itself.
Full license text: LICENSE
Highlighted details: This Software is provided "AS IS". You are responsible for (a) Maintaining appropriate backup copies of any data file that this software is expected to modify, (b) Ensuring that data written to a storage system using this software can be read back in its entirety and with integrity. The author(s) of this product cannot be held responsible for any data loss resulting directly or indirectly from the use of this product.
The core language in the K Reference Manual is fully implemented: native verbs, adverbs, amend, index, apply and assign, functions, conditionals, I/O and communication, system variables and system functions. The Foreign Function Interface allows using Microsoft .NET objects.
When I started this project, getting to the point where it could run all the idioms in my book was only a dream, and actually achieving it in less than 6 months has been an exhilarating experience. This is a milestone that deserves to be released as the beta version of the project.
-
Debugging: My development has been centered around the unit test framework and I haven't needed debugging so I just de-prioritized it, but is it still part of the 1.0 goals.
-
Parsing: The architecture is a simple Tokenize-Parse into AST nodes-Evaluate. It doesn't use a stack or finite state machines, like other interpreters for k and APL-family languages use. The result is not as robust as I'd like. Note: if you run into parsing issues, please report the problem and try to simplify the expression, long and clever one-liners, and even some expressions that aren't that "long and clever", will have a moderate probability of confusing the parser.
-
Simplifying: AI-assisted development was fast, but it also accumulated technical debt at a fast pace. In particular the removal of the "legacy parser" was never completely finished (the original "legacy" parser attempted left-to-right evaluation with backtrack, until that became was eventually unsustainable and it was replaced with the current Long-Right-Scope parser). The end result is code that is more complex than necessary and would benefit from simplification
-
Optimizing: I don't expect ksharp to compete with native implementations of k in terms of performance. Being based on the .NET VM and using managed memory brings some benefits (garbege collected memory usage, no crashes from memory access problems with malformed data, a rich ecosystem, etc) but those come at a cost in performance. That said, there are some performance improvements that can be implemented: Leveraging a global symbol table hashset, or leveraging Linq-to-objects state-machine optimizations before evaluating results.
- I eliminated the k UI from the project goals. I think effort is better spent on making things work with .NET (which opens up many UI choices, like WinForms and Unity).
- Test Suite: 1549/1549 tests passing (100% success rate)
- 🏃 Publish profiles - Generate executables for Windows Mac and Linux
- 🍏 Improved support for command-line editing - Editing now supports Mac and Linux
- 🔃 Improved support for recursions - Added limits to recursion depth (40) and signal instead of crashing.
- 📂 Support for delimited file I/O (May 2026) - Enhanced
0:and1:functionality, fixed5:functionality - 🚀 Improved comparison tolerance (May 2026) - Updated comparison tolerance to better match K compatibility
- 🎯 Full test suite passing at 100% (May 2026) - Successfully resolved parsing issues that were preventing some K idioms from producing correct results
- 🔥 Support for adnouns (May 2026) - The over, scan, each and each-prior adverbs can now be used with nouns (vectors, matrices and tensors) for scatter indexing, transitive closure and state transitions.
K User Manual - Complete K language guide with tutorials and examples
K Reference Manual - Detailed reference for all K functions, operators, and concepts
- Atomic Types: Integer, Float, Character, Symbol, Dictionary, Nil/Self-typed Null, Function, 64-bit Integer
- Collections: List, (complex or mixed-type, including nesting), Integer vector, Float vector, Character vector, Symbol vector, 64-bit Integer vector
- Special Values: Self-typed Null (
0n), infinity (0I,0i,0Ij), negative infinity (-0I,-0i,-0Ij), negative zero (-0.0), integral null/NaN (0N,0n,0Nj) - Type System: Dynamic typing with automatic promotion
- Null Handling: IEEE 754 compliant null propagation
!monadic - enumerate!dyadic, atomic right argument - mod (modulo)!dyadic, vector right argument - rotate#monadic - count#dyadic - take$monadic - format (simple format)$dyadic, character vector right argument - form$dyadic, right argument other than character vector - format (format with specifier)%monadic - invert%dyadic - divide&dyadic - min()- grouping separator,monadic - enlist,dyadic - join-monadic, followed by space - change sign-dyadic - subtract.as last character to variable path - attribute path.inside variable path - descend into value..in variable path - descend into attribute.as index for a dictionary - attribute dictionary.monadic, list (type 0) argument - make dictionary.monadic, character vector argument - execute.monadic, dictionary argument - unmake dictionary.dyadic, first argument is a function - dot apply.dyadic, first argument is a variable - index at depth.triadic, third argument is a verb - apply at depth.triadic, third argument is:- error trap at depth.tetradic - apply at depth with arguments/with whitespace on the left - comment marker'as the single item in an expression - Signal'monadic - Signal:REPL command - resume:monadic - return::with variable name to the left - Global Assign (statement):with variable name to the left - Assign (statement):with monadic verb to the left and no arguments - Monadic apply and assign:with dyadic verb to the left and arguments - Dyadic apply and assign:[]variadic - conditional execute and assign (statement)<monadic - grade up<dyadic - less=monadic - group=dyadic - equals>monadic - grade down>dyadic - more?monadic - uniques?dyadic with list or null (type 6) on the left - find?dyadic with function left argument - inverse function?triadic - apply inverse function@monadic - Is Atom@dyadic, path left argument, character vector right argument - execute at path@dyadic, function left argument - shallow apply@dyadic, variable left argument - shallow index@triadic, third argument is verb - shallow apply@triadic, third argument is:- shallow error trap@tetradic - shallow apply with arguments[]with function to the left - Group and dot apply[]with variable to the left and assignment or apply and assign to the right - Amend[]with variable to the left with no assignment to the right - Group and index at depth\at the start of a line (whitespace allowed,^\s*\\) - Marker for REPL command^monadic - Shape^dyadic - Power_monadic - Floor_as a prefix - system reserved verb or variable_dyadic with integer left argument - drop_dyadic with integer vector left argument - cut{}- group and make function|monadic - reverse order|dyadic - max~monadic, with numeric argument - not (is zero, logical negation)~monadic, with symbol (variable path) argument - attribute handle~dyadic - match+monadic - flip (transpose)+dyadic - add*monadic - first or default*dyadic - multiply- ` before a name or a string literal - symbol marker
""(string literal) enclosing a single item - character""(string literal) enclosing multiple items - character vector;inside grouping (except enclosing quotes) - list separator\ninside grouping (except enclosing quotes) - list separator\nin the REPL, outside grouping/enclosing - evaluate
- Over (
/):+/ 1 2 3 4 5→15(fold/reduce) - Scan (
\):+\ 1 2 3 4 5→(1;3;6;10;15)(cumulative) - Each (
'):-:' 1 2 3 4→(-1;-2;-3;-4)(element-wise) - Each-Left (
\:):1 2,\: 3 4 5→(1 3 4 5;2 3 4 5)(apply operation for each item in left argument, with entire right argument) - Each-Right (
/:):1 2 3 +/: 4 5→(5 6 7;6 7 8)(apply operation with entire left argument, for each right argument) - Each-Pair (
':):,': 1 2 3 4→(2 1;3 2;4 3)(apply operation to consecutive pairs, reversing left and right) - Initialization:
1 +/ 2 3 4 5→15(with initial value) - Adverbs for already modified verbs 🆕:
((1 2);(3 4)),/:\:((9 8);(7 6))→((1 2 9 8;1 2 7 6);(3 4 9 8;3 4 7 6))(adjacent adverbs are nested iterations)
'with matrix/tensor immediately to the left - Scatter Select/with vector of indices immediately to the left - Transitive Closure (index traversal iteration with convergence)/with transition matrix immediately to the left - State Transition (2D iterative index)\with vector of indices immediately to the left - Transitive Closure with trace\with transition matrix immediately to the left - State Transition with trace':with transition matrix immediately to the left - 2D Index each prior
- Simple assign:
a:1 2 3 4 - Slice extraction:
m[3 4;1 2] - Sliced assignment:
m[3 4;1 2]:((8 9);(7 3)) - Modify and assign:
i+:1(increment),x-:2(decrement),n*:3(multiply-assign), etc.
- Anonymous Functions:
{[x;y] x + y} - Function Assignment:
func: {[x] x * 2} - Function Application:
func2 . (4;5),func1 @ 5orfunc2[3;5] - Projections:
add . 5creates{[x] 5 + x} - Multi-statement: Functions can have semicolon-separated or newline-separated statements
- Dependencies - Event system for automatic re-calculation
- Triggers - Event system for execute on change
- UI Attributes not implemented ❌ - .NET FFI is available for UI development, implementation of the K UI is not expected to be implemented.
:[]- Conditional valuedo[]- Fixed iterationif[]- Conditional executionwhile[]- Conditional iteration
- Binary Serialize (
_db): Convert K data structures to binary format - Binary Deserialize (
_bd): Convert binary data back to K data structures
0:monadic - read from file as text0:dyadic - write to file as text1:monadic - read from K data file using memory mapped access1:dyadic - write to file as K data2:monadic - read whole K data file2:dyadic - FFI Load Assembly. See Foreign Function Interface (FFI)3:monadic, list argument - Open IPC Port3:monadic, integer argument - Close IPC Port3:dyadic - IPC set (asynchronous IPC)4:monadic - Type (get variable type)4:dyadic - IPC get (synchronous IPC)5:monadic - String Representation5:dyadic - Append to file as text6:monadic - read from file as raw bytes6:dyadic - write to file as raw bytes
- Internal Info
_d(K dir),_v(K vars),_i(index),_f(self-referent function),_n(null singleton) - Process Info
_k(version),_p(port),_P(PID),_w(who),_u(user) - System Info
_s(space),_h(host),_a(address),_o(os),_c(cores),_r(RAM),_m(mach id) - Trigonometric:
_sin,_cos,_tan,_asin,_acos,_atan - Hyperbolic:
_sinh,_cosh,_tanh - Exponential:
_exp,_log,_sqrt,_sqr - Arithmetic:
_abs,_floor,_ceil,_div(integer division) - Bitwise Operations:
_and,_or,_xor,_rot,_shift - Matrix:
_dot,_mul,_inv,_lsq(least squares regression) - Time Functions: Complete time and date manipulation functions
- _t: current K-time in Seconds since 12:00 AM, January 1, 2035 UTC
- _T: current time in Days since 12:00 AM, January 1, 2035 UTC
- _gtime: Converts K-time to date/time vector ("yyyyMMdd";"hhmmss")
- _ltime: Converts K-time to local time vector with timezone offset
- _jd: Converts date to Julian date (K Julian Date is days since January 1, 2035)
- _dj: Converts Julian date back to yyyyMMdd format
- _lt: Adds GMT-to-local-time offset in seconds to a K-time value
- Search Functions:
_in(search),_bin(binary search) - String Operations:
_sm(string match),_ss(string search),_ssr(string search and replace),_ci(character from integer),_ic(integer from character) - List Operations:
_lin(list intersection indices),_sv(scalar from vector),_vs(vector from scalar),_dv(delete value)_di(delete item) - Pattern Matching: Advanced regex-like pattern matching for
_sm,_ssand_ssrbased on .NET regex, with 1000 ms timeout, customizable via.m.regex.timeout
Operations 3:, 4: - Complete k version 3 Inter-Process Communication system
- 3: (IPC Get/Connection) - Open/close connections and asynchronous messaging
3:(host;port)` - Open connection, returns handle3:handle- Close connectionhandle 3:data- Send asynchronous request
- 4: (IPC Set/Synchronous) - Synchronous remote execution
handle 4:data- Send sync request, returns remote reply(host;port) 4:data` - Open, send, and close in one step
IPC-Related System Values:
- _i - Listening port number (0 when inactive)
- _h - Preferred host for connection tuples
- _w - Current incoming socket handle during .m.g/.m.s/.m.c execution
K Tree Hooks:
- .m.g - Handles synchronous requests (default: executes K code, returns (status;result))
- .m.s - Handles asynchronous requests
- .m.c - Runs when connection closes
Server Startup:
ksharp -i PORT # Start IPC listener in REPL mode
ksharp -i PORT script.k # Start listener, run script, then serve IPCK LRS Compliant
- Left-to-right evaluation of expressions
- Grouped elements (parentheses, brackets, braces) do have precedence
- No verb-specific precedence (e.g., no EMDAS), only positional
- Adverbs, adnouns and brackets bind to the item on its left
- Long Right Scope parsing: Everything to the right of a verb is its right argument (resulting in right-to-left precedence within an expression)
- Parse Tree Verbs 🆕:
- _parse: Converts character vectors to parse tree representations -
_parse "1 + 2"→(`"+", 1, 2) - _eval: Evaluates parse tree representations -
_eval (`"+", 1, 2)→3
- _parse: Converts character vectors to parse tree representations -
- ❌ K UI
`showand`hide - ❌ Attributes related to UI
- ❌ Debugging and Tracing
- ❌ K runtime (.kr) and execution without console
- ✅ Smart Integer Division and exponentiation:
4 % 2→2,2 ^ 3→8(integer, not float) - ✅ 64-bit Long Integers:
123456789012345j(modeled on e333j) - ✅ Compact Symbol Vectors:
`a`b`c(no spaces) - ✅ Compact List and Dictionary Display: Semicolon-separated format
.(`a;1;);(`b;2;)) - ✅ Additional system variables and functions inspired on e333j:
_P_o_c_r_m_y_div(truncating integer division)_and_or_xor_not_rot_shift(bitwise) - ✅ No denorm dictionaries:
.((`a;1);(`a;2)) is .,(`a;2;) and not .((`a;1;);(`a;2;)) - ✅ Parse and eval:
_parse "1 + 2"_eval (`"+";1;2) - ✅ LRS for lists in brackets:
a:3;+[a+:7;a+4]evaluatesa+:7beforea+4becausea+4is outside the scope ofa+:7 - ✅ Improved Compatibility with k version 2:
_n?i→iand execute at contextd@sord[s](symbol left argument and character vector right argument) - ✅ .NET type handling
- Method Invocation: Complete calling of .NET methods from K code with automatic type conversion
- Type Mapping: Automatic conversion K data types -> .NET types, .NET objects copied to K dictionaries with hints
- Static Members: Loaded into
._dotnettree - Performance Optimizations: Type caching and object registry for efficient operations
- Error Handling: Comprehensive .NET exception handling and propagation to K
Assembly Loading
// Load System.Private.CoreLib assembly
"System.Private.CoreLib" 2: `System.String
// Load custom assembly
"MyAssembly.dll" 2: `MyNamespace.MyClass
// The result is a type dictionary containing metadataSyntax: assembly_name 2: type_name
- Left Argument: Assembly name (file path or assembly name)
- Right Argument: Type name (fully qualified .NET type)
- Result: Dictionary containing type metadata, methods, properties, constructors
The _gethint and _sethint verbs provide type marshalling control and object creation hints.
// Create a .NET string object from a k string
s:"hello"
s _sethint `string
// Get type information
s _gethintHint Types:
`bool- System.Boolean, subtype of K int`byte- System.Byte (unsigned int8), subtype of K char (default)`sbyte- System.SByte (int8), subtype of K char`short- System.Int16 (int16), subtype of K int`ushort- System.UInt16 (uint16), subtype of K int`int- System.Int32 (int32), subtype of K int (default for any value other than 0N)`uint- System.UInt32 (uint32), subtype of K long int`long- System.Int64 (int64), subtype of K long int (default for any value other than 0Nj)`ulong- System.UInt64 (uint64), subtype of K long int`float- System.Single (float), subtype of K float`double- System.Double (double), subtype of K float (default)`object- System.Object (object), subtype of K dictionary`datetime- System.DateTime, subtype of K int or K float`timespan- System.TimeSpan, subtype of K int or K float`dictionary- System.Collections.Hashtable, subtype of K dictionary (default)`list- System.Collections.Generic.List<System.Object>, subtype of K lists and vectors (default for all except character vectors)`string- System.String, subtype of K symbol and K character vector (default)`stringbuilder- System.Text.StringBuilder, subtype of K string`null- System.DBNull, subtype of K int and long int (default conversion for 0 and 0N)`method- System.Delegate, subtype of K function
K3CSharp includes automatic object lifecycle management with explicit disposal capabilities.
// Bind .NET dll
complex:`System.Runtime.Numerics.dll 2: `System.Numerics.Complex
// K verb constructor
complex_new:complex[`constructor]
// Create object
c1:complex_new[2;3]
// Dispose object when done
_dispose c1
// Check object status (returns handle information)
c1._thisNOTE: When a .NET Object is instantiated, a copy of its data will be mapped onto a K dictionary. This dictionary is an independent copy and changes will not be propagated back to .NET. Changing the .NET object must be done through accessors and methods.
Object Registry:
- Thread-safe global object tracking
- Automatic handle generation
- Memory management integration
- IDisposable pattern support
The ._dotnet global tree stores loaded assemblies and type information for efficient reuse.
// Access static methods for loaded assemblies
conj_func: ._dotnet.System.Numerics.Complex.Conjugate
// Enumerate metadata
!._dotnet.System.Numerics.Complex
// Type information is cached for performanceTree Structure:
- Numeric indices: Assembly references
- Symbol keys: Assembly names
- Nested dictionaries: Type metadata
Call .NET methods on object instances using dot notation.
// Create object
str: "hello" _hint `object
// Call methods (when method invocation is fully implemented)
str.ToUpper // Returns "HELLO"
str.Length // Returns 5
str.Substring(0;2) // Returns "he"
// Access properties
str.Length // Property access
str.Chars[0] // Indexer accessMethod Calling Features:
- Instance method invocation
- Static method calls
- Property getter/setter access
- Field access
- Indexer support
- Argument marshalling
The FFI system provides comprehensive error handling:
// Invalid assembly
"NonExistent.dll" 2: `SomeType // Error: Assembly not found
// Invalid type
"System.Core" 2: `NonExistentType // Error: Type not found
// Method errors
obj.NonExistentMethod // Error: Method not foundError Types:
- Assembly loading failures
- Type resolution errors
- Method invocation exceptions
- Invalid argument types
- Object disposal errors
- Assembly Caching: Loaded assemblies are cached in
_dotnettree - Object Registry: Efficient handle-based object tracking
- Type Marshalling: Optimized for common types
- Memory Management: Automatic garbage collection integration
K3CSharp/
├── ApplyTweaks/ # Tool MCP Server for applying known_differences.txt to a result
├── K3CSharp/ # Core interpreter implementation
├── K3CSharp.Comparison/ # k.exe comparison framework
├── K3CSharp.IPC/ # k.exe Inter-Process Communication (Contributed by Michal Wallace @tangentstorm)
├── K3CSharp.IPC.Tests/ # k.exe IPC test framework (Contributed by Michal Wallace @tangentstorm)
├── K3CSharp.MCP/ # Tool MCP Server for running a ksharp session (Contributed by Michal Wallace @tangentstorm)
├── K3CSharp.Comparison/ # k.exe comparison framework
├── K3CSharp.Tests/ # Unit tests
├── KMCPServer/ # Tool MCP Server for running an external K/Q interpreter with a command or a script
└── known_differences.txt # Known differences configuration
- Lexer.cs: Tokenizes input into tokens with underscore ambiguity resolution
- Parser.cs: Recursive descent parser building AST with adverb support
- Evaluator.cs: AST traversal and evaluation with complete operator system
- K3Value.cs: Type system and value operations
.NET 8.0 SDK is required to build and run ksharp.
# Download and install .NET 8.0 SDK
# Visit: https://dotnet.microsoft.com/download/dotnet/8.0# Install .NET 8.0 SDK
wget https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
sudo apt-get update
sudo apt-get install -y dotnet-sdk-8.0# Install .NET 8.0 SDK
sudo rpm -Uvh https://packages.microsoft.com/config/rhel/8/packages-microsoft-prod.rpm
sudo dnf install -y dotnet-sdk-8.0# Install .NET 8.0 SDK using Homebrew
brew install dotnet-sdk@8
# Or download installer from:
# https://dotnet.microsoft.com/download/dotnet/8.0# Clone repository
git clone https://github.com/ERufian/ksharp.git
cd ksharp\K3CSharp
# Restore dependencies (optional)
dotnet restore
# Build solution (optional)
dotnet build
# Run
dotnet run# Clone repository
git clone https://github.com/ERufian/ksharp.git
cd ksharp/K3Csharp
# Restore dependencies (optional)
dotnet restore
# Build solution (optional)
dotnet build
# Run
dotnet run# Clone repository
git clone https://github.com/ERufian/ksharp.git
cd ksharp/K3CSharp
# Restore dependencies (optional)
dotnet restore
# Build solution (optional)
dotnet build
# Run
dotnet run# Clone repository
git clone https://github.com/ERufian/ksharp.git
cd ksharp/K3CSharp
# Restore dependencies (optional)
dotnet restore
# Build solution (optional)
dotnet build
# Run
dotnet run"dotnet: command not found"
- Ensure .NET 8.0 SDK is installed and in PATH
- Restart terminal after installation
- Verify with
echo $PATH(Linux/macOS) orecho %PATH%(Windows)
"Cannot find project or solution file"
- Ensure you're in the correct directory containing
.csprojor.slnfiles - Use
ls(Linux/macOS) ordir(Windows) to verify files
Build errors on Linux/macOS
- Ensure all required packages are installed
- Try
dotnet cleanfollowed bydotnet build - Check file permissions:
chmod +x *.sh(if using shell scripts)
Performance issues
- Use release build:
dotnet run -c Release - For large datasets, consider increasing memory:
dotnet run --environment DOTNET_GCHeapCount=1
Windows PowerShell:
# Set execution policy for scripts (if needed)
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUserLinux/macOS Shell:
# Make script files executable
chmod +x *.sh
# Use bash explicitly if needed
bash script.shmacOS Specific:
# If using zsh (default on modern macOS)
echo 'export PATH=$PATH:$HOME/.dotnet' >> ~/.zshrc
source ~/.zshrcPlease include:
- Issue Summary
- Description of the problem
- Expected Result
- Steps to reproduce, with a code snippet whenever possible
Please note: I use a Windows 10 machine for development. OS-specific issues should be very rare, but I will not be able to address issues that can be reproduced only on a different OS
VERY IMPORTANT By submitting a contribution you agree that it will be subject to the terms of the MIT License
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Run comparison framework to verify k.exe compatibility
- Submit a pull request
This ksharp interpreter implementation was coded originally by SWE-1.5 and 1.6 with significant contributions from Kimi K-2.5 and 2.6 and Claude Opus/Sonnet 4.5, 4.6 and 4.7 based on specifications, direction, prompts, comments and manual fixes provided by Eusebio Rufian-Zilbermann.
- Michal Wallace (@tangentstorm)
- Complete K version 3 IPC (Inter-Process Communication) system including TCP-based messaging, K tree hooks (.m.g, .m.s, .m.c), and the 3:/4: IPC verbs
- MCP Server for agent interoperation with a ksharp persistent session
- Various bugfixes
In addition to direct contributors, the following people have been fundamental to the creation and development of this project. I am very thankful for their influence. Without them, it is possible that this interpreter would not exist.
- Arthur Whitney - Creator of the K and Q languages
- Adam Jacobs - His comments and insight over the years regarding the K interpreter have provided invaluable inspiration and information.
- Joel Kaplan - He gave me the chance to learn K. His warning over a decade ago "Once you learn K it will change your mind and you will never think about programming the same way" has proven to be remarkably accurate.
- Stevan Apter - His K parser at nsl.com has been a really helpful source of inspiration and reference. Stevan, together with Sasha Katsman and Michael Rosenberg, greatly helped in my understanding of traditional "idiomatic K".
- John Earnest - His oK interpreter was an important inspiration for deciding to develop ksharp. Additionally, his regular questioning of AI assisted development has been an outstanding motivation for pushing the limits and exploring what's possible.
This project is ksharp in all lowercase, because it is an interpreter for the k language written in C sharp. Unfortunately there are other projects with very similar names that differ just in capitalization, like Ksharp kSharp, KSHarp, etc. This project is not related to any of them and the name ksharp is not intended to claim any relationship to any of them, the only implied relationships are the k language (as the model) and C sharp (as the tool)
🚀 Try it out: dotnet run and start exploring ksharp!