Open Q Language

Core

The shared k/q core: evaluation, lexis, types, verbs, adverbs, functions

Required One chapter of the Open Q Language specification. README.txt states what must be implemented, how conformance is defined, and how rule IDs work.

This chapter specifies the core that the k and q surface dialects share: the evaluation model, lexical grammar, type system, verbs, adverbs, functions, and control flow. The q surface adds keywords and pattern matching (q.txt) and the query sublanguage (qsql.txt); neither is repeated here.

CORE-00011. Evaluation model

Right to left, NO operator precedence. A verb applies to the whole expression on its right. Parentheses and brackets are the only grouping.

2*1+1        is 2*(1+1)      = 4       not (2*1)+1
5=2+3        is 5=(2+3)      = 1b      not (5=2)+3

Evaluation is strictly eager: every subexpression yields a concrete value at once. There are no lazy plans. The one lazy construct is the conditional $[c;t;f] (section 9.7), where only the taken branch runs.

Verbs are OVERLOADED BY ARITY, resolved at apply time, not by the lexer:

monadic   one argument, prefix     -x   ,x   #x
dyadic    two arguments, infix     x-y  x,y  x#y

A term's role (noun / verb / adverb) is lexical; its arity (monad vs dyad) is decided by how many operands reach it during evaluation. The parser therefore builds an arity-agnostic tree and defers monad/dyad selection to the evaluator (see Train, section 9.9).

CORE-00022. Dialect: k versus q

One shared core is parsed in two surface dialects, selected per line:

q)expr        parse this line as q
k)expr        parse this line as k

A .k file loads entirely as k. A script is split into maximal same-dialect runs.

k is the terse layer. Relative to q it:

  • DROPS the q-only surfaces: qSQL templates (select/exec/update/delete), q 4.1 pattern-match forms, and word-spelled infix keywords.
  • ADDS k's defining rule: a bare glyph in monadic position is that glyph's MONADIC OVERLOAD. #x is count, !x is til/key, $x is string, |x is reverse. (section 9.10). v: is the explicit spelling of a verb's monad as a value.

Everything else is the common core and is identical in both dialects: literals, lambdas, adverbs, brackets, $[c;t;f], if/do/while, assignment and amend.

In k mode the word-spelled infix verbs of q are demoted back to plain identifiers: mod xbar and or become names; and/or/mmu do NOT lex to & | $. div and xexp remain infix (they are k-native).

Out of scope for the k surface (q-only): qSQL queries, the pattern conditional :[value;pat;res;...], and the keyword-to-verb rewrite tables. A k parser need not implement these.

CORE-00033. Lexical grammar

The grammar is scannable by a hand-written byte scanner; no regex or tables are needed. Newlines are significant and are emitted as tokens.

CORE-00043.1 Whitespace, comments, newlines

  • Space and tab separate tokens.
  • A newline is a STATEMENT SEPARATOR at the top level. Inside brackets ( ) [ ] { } the parser tracks depth and treats a newline as whitespace. (Exception: in k mode a newline inside ( ) separates list items like ; .)
  • A / that starts a token (preceded by whitespace or line start) begins a comment to end of line. A / adjacent to a noun is the over adverb, not a comment.
  • A line that is a single / opens a block comment; a single \ closes it.
  • Trailing whitespace and blank lines are insignificant.

CORE-00053.2 Identifiers

A letter or . followed by letters, digits, . and _ . Names may be dotted (namespaced): .cq.load , .Q.fs . A leading . means the global/root namespace. Named builtins (count, sum, all, ...) lex as identifiers, NOT as verbs; they resolve to functions at evaluation time.

CORE-00063.3 Numeric atoms and their suffixes

Default integer literal is LONG (64-bit). Default decimal is FLOAT (64-bit). Suffix letters set the type:

b   boolean / bit          1b   0b   0110b
x   byte (hex)             0x1f            (also vectors, below)
h   short   (i16)          42h
i   int     (i32)          42i
j   long    (i64)          42j    (same as bare 42)
e   real    (f32)          3.14e   1e
f   float   (f64)          3.14f   20.   (bare 3.14 is already float)

Scientific notation uses lowercase e only: 1e9 is float. Uppercase 1E3 is an error. A leading - before a numeric literal is a sign, not the subtract verb, when it is immediately followed by a digit or a null/inf marker.

CORE-00073.4 Nulls and infinities (case sensitive)

Null marker 0N , infinity marker 0W (uppercase). Float forms use lowercase 0n / 0w . A type suffix selects width:

type     null      +inf      null sentinel      +inf sentinel
short    0Nh       0Wh       i16::MIN           i16::MAX
int      0Ni       0Wi       i32::MIN           i32::MAX
long     0N  0Nj   0W  0Wj   i64::MIN           i64::MAX
real     0Ne       0We       f32 NaN            f32 +Infinity
float    0n  0Nf   0w  0Wf   f64 NaN            f64 +Infinity
guid     0Ng       (none)    all-zero bytes     --

Bare 0N / 0W default to LONG. Bare 0n / 0w default to FLOAT. -0w / -0Wi etc. are negative infinity (the leading - is a sign). boolean, byte, and char have NO null and NO infinity (as in kdb).

CORE-00083.5 Byte and bit literals

Byte atom:    0x1f            one hex pair
Byte vector:  0x0102 , 0x    a run of hex pairs, or empty
Bit atom:     1b             boolean true
Bit vector:   0110b          four booleans; a trailing b over a digit run
                             makes the whole run boolean (0 0 1b)

CORE-00093.6 Temporal literals

THE EPOCH IS 2000.01.01. Every absolute temporal value counts from midnight on that date, in its own unit, as a signed integer; earlier instants are negative. "j"$2000.01.01 is 0 and "j"$1970.01.01 is -10957. An implementation that stores temporals on the Unix epoch must still cast, compare and display them as if the origin were 2000.01.01.

kind        code  unit                    literal
timestamp   12    ns since epoch          2026.06.12D12:00:00.000000000
month       13    months since epoch      2026.06m
date        14    days since epoch        2026.06.12
datetime    15    days since epoch, f64   2026.06.12T12:00:00.000
timespan    16    nanoseconds (DURATION)  0D01:30:00.000000000
minute      17    minutes since midnight  12:00
second      18    seconds since midnight  12:00:00
time        19    ms since midnight       12:00:00.000

timespan, minute, second and time are durations or times-of-day: they have no epoch. Only timestamp, month, date and datetime are absolute.

Disambiguation: Y.M.D form: trailing D -> timestamp, trailing T -> datetime, neither ->

date.  (datetime is the one float-backed temporal: 2000.01.02T06:00:00
is 1.25. It is deprecated but not removed.)

HH:MM family, by structure: 2 fields -> minute; 3 fields -> second;

3 fields + .fff (<=3 fraction digits) -> time; MORE than 3 fraction
digits promotes to timespan (12:00:00.123456 is a timespan).

Suffix coercion t / v / u rescales a bare HH:MM... to time / second /

minute respectively.

Temporal nulls: 0N plus a kind suffix -> i64::MIN. Suffix letters:

d date   m month   p timestamp   n timespan
t time   v second  u minute      z datetime

Temporal infinities: 0W plus a kind suffix -> i64::MAX, for every kind above (0Wd 0Wm 0Wp 0Wn 0Wt 0Wu 0Wv). 0Wz is float-backed and displays lowercase as 0wz. There is NO 0Wg: guid has a null but no infinity.

CORE-00103.7 Characters and strings

Double quotes delimit a char vector: "hello". Escapes \" \\ \n \t \r and \NNN octal. A ONE-character string "a" evaluates to a CHAR atom (type -10); a multi-character string is a CHAR VECTOR (type 10). A string is exactly a list of chars: "foo" ~ ("f";"o";"o") is 1b.

CORE-00113.8 Symbols

Backtick then an identifier-ish body: `ibm . The backtick is not part of the value. An empty symbol is a lone backtick: ` . A run of adjacent symbols is a symbol vector: `a`b`c . Symbols are interned. File / IPC paths are symbols beginning with a colon:

`:path/to/file        local file path
`:host:port           IPC endpoint

CORE-00123.9 Glyph verbs

Only these glyphs are verbs. Everything word-spelled is an identifier.

+  -  *  %  =  <>  <  >  <=  >=  ,  !  #  _  ^  @  .  &  |  ~  ?  $

Keyword-spelled infix verbs (dyadic only, no monad), still verbs:

div  mod  xexp  xbar  in

(In k mode: div and xexp stay verbs; mod xbar and or in become plain identifiers per section 2.) File verbs:

0:   text  (parse/format/write delimited text)
1:   binary (fixed-width read; raw byte write)

The colon as a value:

:    identity monad; as a dyad-value it is "replace" (returns its right
     argument), used inside amend @[x;i;:;y].

CORE-00133.10 Adverbs (iterators)

'    each
':   each-prior
/    over   (fold / reduce)
\    scan
\:   each-left
/:   each-right

CORE-00143.11 Punctuation tokens

: ; { } [ ] ( ) and Newline

CORE-00153.12 System command

A line beginning with \ (not a block-comment close) is a system command: \cmd args... (the leading \ is not part of the command name).

CORE-00163.13 Vector runs (a lexer/parser coalescing rule, key for a fast parser)

Adjacent same-family literals separated only by spaces coalesce into ONE typed vector node at parse time; no ( ; ) needed:

1 2 3                long vector
1 2 3h               short vector (a suffix anywhere sets the run type)
0x01 0x02   ==  0x0102       byte vector
`a`b`c               symbol vector
0 0 1b               bool vector
2026.01.01 2026.01.02        date vector

Type promotion within a numeric run: float > real > int > short > long; the widest present wins, and null/inf sentinels remap to that width (0N 2 3i becomes 0Ni 2 3i). An incompatible element ends the run. This is why a simple k parser scans for a maximal literal run before falling back to general expression parsing.

CORE-00174. Types (the runtime value representation)

type x returns the short type code: a vector is the positive code, an atom the negative. Code 3 is unused. Codes 20h and above are enumerations (section 4.6).

CORE-00184.1 Atoms

code  char  type        variant       literal
-1    b     boolean     Bool          1b 0b
-2    g     guid        Guid          0Ng, "G"$"...", n?0Ng
-4    x     byte        Byte          0x1f
-5    h     short       Short         42h
-6    i     int         Int           42i
-7    j     long        Long          42  42j
-8    e     real        Real          3.14e
-9    f     float       Float         3.14  3.14f
-10   c     char        Char          "a"
-11   s     symbol      Symbol        `ibm
-12   p     timestamp   Temporal      2026.06.12D12:00:00.000000000
-13   m     month       Temporal      2026.06m
-14   d     date        Temporal      2026.06.12
-15   z     datetime    Temporal      2026.06.12T12:00:00.000
-16   n     timespan    Temporal      0D01:30:00.000000000
-17   u     minute      Temporal      12:00
-18   v     second      Temporal      12:00:00
-19   t     time        Temporal      12:00:00.000

CORE-00194.2 Typed (simple, homogeneous) vectors

The positive of the atom code. Each has a dedicated Value variant: BoolVec GuidVec ByteVec ShortVec IntVec LongVec RealVec FloatVec CharVec (a char vector is a string). A simple vector is homogeneous; appending a value of another type promotes it to a general list (section 4.3).

CORE-00204.3 General (mixed) list

type code 0: a list whose elements may be of any type. Written with ( ; ):

(1; 2.5; "foo"; `sym)

Empty list: () Single element (expr) is GROUPING, not a one-list. To enlist one item use ,x or (x;). A HOLE anywhere makes it an enlist PROJECTION, not a list: (1;;3) , (a;b;) . A nested list of vectors is how MATRICES are represented (section 4.7).

CORE-00214.4 Dictionary

type code 99. No dict literal; built with ! :

`a`b`c!1 2 3

keys and values are each any value (usually two conforming vectors).

CORE-00224.5 Table

type code 98: named, equal-length column vectors (a flipped column-dictionary). Table literal:

([]  name:col; name:col; ...)          plain table
([keyname:col] name:col; ...)           keyed table

flip (the monad of +) transposes a column dict into a table. A keyed table is a dictionary whose keys and values are BOTH tables, and reads as type 99, not 98.

CORE-00234.6 Foreign keys / enums

`d$`a`b enumerates symbols against the symbol vector named d, yielding an enumeration: type 20h for the first domain, 21h for the next, and so on. value recovers the symbols; the stored representation is an int index into the domain. An enumerated column is how a symbol column is held on disk (storage.txt). A foreign key is an enumeration whose domain is a keyed table's key column.

CORE-00244.7 Matrices / nested types

No dedicated matrix type. A matrix is a general list whose elements are equal-length vectors (rectangular by convention only). Indexing supports an elided axis: mat[;1] selects column 1 across every row. Any list/vector may nest a list/vector to arbitrary depth; type applies at each level.

CORE-00254.8 Function and singleton values (each has a type code)

100   lambda                        {[x;y] x+y}
101   verb monad, and unit (::)     #:  -:  .:  ::
102   verb / builtin as a value     (+)
103   iterator as a value           (')  (/)
104   projection                    +[2]
105   composition                   '[not;null]
106   each          f'
107   over          f/
108   scan          f\
109   each-prior    f':
110   each-right    f/:
111   each-left     f\:
112   dynamic load  2:

Each iterator gets its OWN code (106-111); they are not one "derived" code. 101 is shared by a verb's monad and by unit.

CORE-00264.9 Null and infinity summary

Integer nulls are sentinel min-values; integer +inf are sentinel max-values. Float null is NaN, float inf is IEEE infinity. Temporal null is i64::MIN. boolean/byte/char have no null. See section 3.4 for literals.

CORE-00275. Verbs — monadic and dyadic meanings

Each glyph is overloaded: the monad (prefix, one arg) and the dyad (infix, two args) are different operations. In k, the bare glyph in monadic position IS the monad (section 9.10). In q you usually spell the monad with a keyword.

glyph   monadic                         dyadic
+       flip / transpose                add
  • negate subtract
*       first                           multiply
%       reciprocal                      divide (result is always float)
=       group (value -> indices)        equal (loose: 42=42.0 is 1b)
<>      --                              not equal
<       grade up (iasc) for lists;      less than
          hopen for a `:target symbol
>       grade down (idesc) for lists;   greater than
          hclose for a handle
<=      --                              less than or equal
>=      --                              greater than or equal
,       enlist (wrap atom in a list)    join / concatenate; tables append,
                                          keyed tables upsert
!       til (for an int) / key (of a    make dict keys!values; n!table keys
          dict or namespace)              by first n cols; 0!kt unkeys.
                                          Reserved codes: 0N! -3! display;
                                          -8! -9! -11! -21! -22! serialize
#       count                           take / reshape (cycling; negative =
                                          tail). Symbol left = set attribute
                                          `s# `u# `p# `g# ; the attribute
                                          PERSISTS and attr reports it
_       floor                           drop / cut (negative = drop tail);
                                          `k _ dict drops keys
^       null (is-null predicate)        fill (replace nulls in y with x)
@       type                            index-at / apply-at. 3-arg: trap
                                          @[f;x;e] or amend @[x;i;f]. 4-arg:
                                          amend-with-value @[x;i;f;y]
.       value / eval (symbol gets;      index-at-depth / apply f . args.
          string evals; list applies;    3/4-arg: trap or amend at depth
          dict -> values)
&       where (mask -> indices)         min / and (boolean stays boolean)
|       reverse                         max / or
~       not                             match: structural equality, TYPE
                                          INCLUDED (1.0~1 is 0b). Floats
                                          compare tolerantly: values within
                                          2^-43 relative are equal, so
                                          1.0~1+2 xexp -44 is 1b but
                                          1.0~1+2 xexp -43 is 0b
?       distinct                        find (first index). int-left: roll /
                                          deal. 3-arg: vector conditional
                                          ?[mask;x;y]. 4/5-arg: functional
                                          select / exec (q surface)
$       string                          cast `kind$v ; also matrix multiply
                                          (mmu); $[c;t;f;...] scalar cond
                                          when 3+ args
:       identity (returns its arg)      replace (returns y) -- used in amend

Keyword-spelled dyadic verbs (no monad):
div     integer divide (floor; result type follows the left operand)
mod     modulo (floor; result takes the divisor's sign)
xexp    power (float): 2 xexp 4 is 16
xbar    bucket down to a multiple of n
in      membership: x in y -> boolean
0:      delimited text: parse / format / write
1:      fixed-width binary read; raw byte write

Traps for an implementer:

  • % is ALWAYS float: 35%5 is 7f. Use div for integer division.
  • mmu is float-only. Integer operands are a 'type error, NOT promoted: 1 2 mmu 1 2 signals type. Cast first.
  • Attributes are real state, not a hint. `s#1 2 3 sets `s and attr reports it; asc sets `s as a side effect. An implementation that validates the attribute but discards the flag does not conform.
  • Match ~ is type-strict but float-tolerant; equality = is type-loose (42=42.0 is 1b) and equally tolerant.

CORE-00286. Adverbs / iterators

An adverb modifies a verb or function, producing a DERIVED function. It binds to the term on its LEFT.

glyph  name         behaviour
'      each         monadic: map f over items.  dyadic: zip f over pairs.
':     each-prior   apply f to each adjacent pair (x_i, x_i-1).
/      over         fold/reduce to one result. With a seed: x f/ y.
                    4-arg over of @ or . is an iterated amend.
\      scan         like over but returns every intermediate result.
\:     each-left    fix the right arg, vary the left over its items.
/:     each-right   fix the left arg, vary the right over its items.

Noun overloads: when the LEFT operand of \: or /: is a NOUN (not a function),

x \:  is the verb vs  (split / decode)
x /:  is the verb sv  (join  / encode)

Common derived words built from adverb+verb (available as names):

sums  +\      prds  *\      maxs  |\      mins  &\      fills  ^\
raze  ,/      deltas  -':   ratios  %':

prev is :': and next is the same each-prior over the reversed list.

CORE-00297. Identifiers, builtins, namespaces

Named builtins are ordinary identifiers resolved at eval time (the lexer does not special-case them). The library is large: aggregates (count sum avg min max first last distinct ...), list ops (reverse rotate raze sublist ...), ordering and search (asc desc iasc idesc rank bin group where ...), math (abs signum sqrt exp log sin cos ... and or), stats and moving windows (var dev med wavg mavg msum mcount ema ...), text (lower upper trim like ss ssr md5 ...), dict/table (key value cols flip meta xasc xkey xgroup insert upsert ...), joins (lj ij uj ej aj wj pj asof fby ...), reflection/system (parse eval value get set save load system exit ...), IO/IPC/JSON (hopen hclose read0 read1 ...).

Namespaces are dotted: a name may live under .Q.* .z.* .j.* or any user or implementation namespace (runtime.txt). A leading . anchors at root. A dotted name in a query keeps its last segment as the column name.

A k parser does not need to know the builtin set: unknown identifiers are just name references resolved later. Only glyph verbs, keyword verbs, and adverbs are syntactically special.

CORE-00308. Lists, dictionaries, tables — syntactic summary

()                    empty general list
(a; b; c)             general list of three expressions
(a)                   grouping, NOT a list
,a                    enlist a (one-element list)
1 2 3                 typed vector (run coalescing, section 3.13)
`a`b`c                symbol vector
"abc"                 char vector (string)
`a`b!1 2              dictionary (! operator)
([] a:1 2; b:3 4)     table
([k:1 2] v:3 4)       keyed table
(1 2;3 4;5 6)         nested list (a matrix by convention)

Indexing:

x[i]        index / apply           x[i;j]     index at depth 2
x[;j]       elided first axis (all rows, column j)
x . (i;j)   index at path
x[i]:v      indexed amend (see 9.4)

CORE-00319. Syntactic forms (what the parser builds)

The parser is precedence-free recursive descent, right to left. Its AST is the practical grammar; the main node kinds follow.

CORE-00329.1 Application and indexing

head[a;b;...] applies head to the bracketed args. Juxtaposition head arg is also application. Indexing a list/dict/table uses the same bracket form. f . args applies with an argument LIST. f@x is monadic apply (same as f x).

CORE-00339.2 Projection and elision

Supplying fewer args than a function's rank, or leaving a bracket slot empty, yields a PROJECTION (a partially applied function):

f[;2]        project on the first argument
(+)[2]       project the dyad + to add-2  (equivalent to  2+ )

An empty slot is an Elision node. Distinguish it from :: (GenericNull / identity value): @[f;::;e] applies, f[;2] projects.

CORE-00349.3 Assignment

name:expr        assign (local inside a lambda, else global)
name::expr       assign to the GLOBAL binding even inside a lambda

Assignment is parsed INSIDE expr, so it nests and binds the whole rest of the line to its right: c:3+b:2+a:1 assigns a=1, b=3, c=6. A bracket block as a plain : value is rejected: x:[1;2;3] is an error.

CORE-00359.4 Amend assignment

name verb:expr   is  name: name verb expr        r,:x  appends x to r
name verb::expr  amends the GLOBAL binding.

Indexed amend desugars to functional amend on the same name:

name[i]:v        -> name:@[name;i;:;v]
name[i;j]:v      -> name:.[name;(i;j);:;v]
name[i]op:v      -> name:@[name;i;op;v]

These target the existing binding (global if no local), they do not declare.

CORE-00369.5 Return and signal

:expr            explicit return from a lambda body (statement position only)
'x               signal / throw: raise an error whose text is x (a string or
symbol). (Distinct from the each adverb, which follows a
function term.)

CORE-00379.6 Lambdas

{expr}                     implicit params x, y, z (up to 8: x y z then more)
{[a;b] expr; expr}         explicit params; body is ;-separated statements,
                           value is the last statement
{[] expr}                  niladic (no args)

A lambda's source text is retained so it can be re-emitted (e.g. serialized over IPC as kdb type 100). Free names resolve to enclosing/global scope; local names are resolved to frame slots at parse time for fast access.

Parameter PATTERNS (q 4.1, available in the shared core; a k parser may omit the exotic ones): a param may be a plain Name, a Blank _ , or a destructuring List / Dict pattern. The everyday forms are the plain name and [] .

CORE-00389.7 Conditional (an expression, lazy)

$[c;t;f]              if c then t else f
$[c1;e1;c2;e2;...;d]  multi-way; the first true branch's result; d default

Only the taken branch is evaluated. With fewer than 3 args, $ is cast, not conditional.

CORE-00399.8 Control flow (statements, no value)

if[test; e1; e2; ...]     run the body when test is true; no else, no value
do[n; e1; e2; ...]        run the body n times
while[test; e1; e2; ...]  run the body while test is true

These are recognized as a leading keyword directly followed by [ .

CORE-00409.9 Blocks and trains

[e1;e2;...;en] a statement block: evaluate each in order in the enclosing

scope, yield the last. Empty [] yields unit (::).

A juxtaposition of 2+ terms is a TRAIN. The evaluator resolves application and infix by each term's ARITY: a dyadic middle term applies infix (count each x), a monadic one applies prefix (count distinct x). This is the core reason parsing stays arity-agnostic and dispatch is deferred.

CORE-00419.10 The k monadic-glyph rule (k's defining feature)

In k, a bare glyph with a single operand on its right is that glyph's MONADIC overload, parsed as a VerbMonad application:

#x   count          !x   til / key       $x   string
|x   reverse        &x   where            *x   first
^x   null           ,x   enlist          =x   group    ...

The value form (a monad as a first-class value) is written glyph then colon:

#:   count as a value        -:   negate as a value      .:   value/eval

Applied forms parse to a Monadic node; the bare v: form parses to VerbMonad.

CORE-004210. Notes for the parser implementer

  • Two passes are enough: a byte-scanning lexer, then a precedence-free right-to-left recursive descent. No precedence table, no shunting yard.
  • Arity is NOT a parse concern. Build monad/dyad-agnostic nodes (a verb term, its left operand if present, its right operand); let the evaluator pick the overload by counting operands. Only bracket application fixes arity early.
  • Coalesce literal runs (section 3.13) in the lexer or a thin pre-pass; it is the single biggest simplifier and the biggest speed win for real k code.
  • Track bracket depth so newlines are statement separators only at depth 0.
  • Resolve lambda-local names to integer slots at parse time; global/free names stay as name references. This keeps evaluation a slot index, not a hash.
  • The lexer must report "incomplete" (unterminated string, unbalanced brackets) distinctly from "malformed" so a REPL can keep reading lines.
  • Right-to-left plus assignment-inside-expr means an assignment binds the entire remaining right side; do not special-case it out of the expression grammar.

CORE-004311. Display form

-3! renders a value as text. The result is the K display form and is a distinct, observable part of the language: it is what a console echoes, what a serialized lambda carries, and what error and log output embed.

It is NOT the same as q source. A bare monadic glyph is the monad in k but not in q (section 9.10), so -3! output round-trips through the k parser and not through the q one:

-3!enlist 1              is  ,1        not  enlist 1
-3!flip `a`b!(1 2;3 4)   is  +`a`b!(1 2;3 4)
value "k)+`a`b!(1 2;3 4)"   works
value    "+`a`b!(1 2;3 4)"   signals

An implementation MUST render the K form: enlist 1 renders as ,1 and a table renders as +dict. An implementation that renders q source instead does not conform to this section.

Float rendering depends on the display precision \P; value equality does not. -3!sqrt 2 and string 3.14 are therefore specified at the default precision \P 7. Every other rule in this specification is precision-independent.

END

Source: spec/core.txt