1 + 1 / basic arithmetic can be done with infix notation 5 * 7 2 - 4 3 % 2 / division is done with % since / serves other purposes like the beginning of a comment! :D 2 ! 37 / This is 37 modulo 2. Note that the modulus is on the left. (explanation to follow .. maybe) 3 * 4 + 1 / evaluation happens from right to left. There is no precedence between operations. 3 * (4 + 1) (3 * 4) + 1 / Use parentheses when you want to control the order of evaluation 1 2 3 + 3 0 2 / rank polymorphism means these operations work for vectors of equal length 1 2 + 3 0 2 / you get an error if these vectors are not equal length 1 + 3 0 2 / by scalar extension however, you can add scalars to vectors. / it's as if the scalar were repeated until the necessary length # 9 8 4 5 / length counts the length of a vector / unlike the previous examples, # takes one argument. single arguments are always taken to the right 2 4 , 9 0 4 / concat joins two vectors # 2 4 , 9 0 4 #2 4,9 0 4 / spaces around built-in functions (called verbs in the lingo) are not necessary / but we'll use them here occasionally for a bit longer ,1 / enlist puts its argument in a list / this shows the meaning of "," is overloaded. this happens a bunch in k, but often the meanings are related # ,1 / this is a list of length 1 # 1 / hmm... scalars have length?? take this on faith for now that this comes in handy @ 1 / @ returns the type of its argument, this is an "int". / oh, verbs which take one argument are called "monadic" and ones which take two "dyadic" @ ,1 / this is a list of ints. Capitals indicate lists. (lists, vectors, same thing) ,3 7 9 / You can enlist a list # ,3 7 9 / this is a list of length 1 * 3 7 9 / this takes the "head" of the list. i.e. the first element. / (not related to multiplication but another case of overloading) *,3 7 9 / the head of an enlisted list is ... the list. makes sense. (,1 2 3),(,3 5 0) / the concat of two enlisted lists to form a list of lists (1 2 3;3 5 0) / (Parens around semi-colon separated items form explicit lists) #(,1 2 3),(,3 5 0) / .. of length two (,1 2 3), ,3 5 0 / the parentheses on the right are not necessary because of right-to-left evaluation (0 1 3;99;6 1) / explicit lists need not be uniform (neither length nor type) @"string" / strings are lists (capital C) of chars. @"s" / a single char is also surrounded with double quotes. (this can be a bit confusing at first) @,"s" / to get a list of a single char, use enlist ("n";"i";"c";"e") / double quotes are just syntactic sugar to make lists of chars. "o","k" / Oh yeah! Concat can also concatenate two scalars "s","tring" / ... or a scalar to a vector. Note that scalar extension does *not* apply here. ("o";,"k";4 9 2) / An even more mixed array #'("o";,"k";4 9 2) / verbs can be modified to perform derived functionality / here ' (called each) modifies length to perform length on each of the elements of its list argument ,'4 5 6 / each is called an adverb and can be applied to other verbs / enlist each element of 4 5 6 to get a list of three one-element lists 3 9 2,'-1 -4 0 / each can be applied to dyadic verbs and pairs up the elements of both args 0,'3 4 1 / scalar extension applies to such pairing as well 0,/:3 4 1 / but there is a more explicit way to indicate that the left argument stays the same / this adverb is called eachright 1 0,/:3 4 1 / It's useful when scalar extension doesn't apply 1 0,\:3 4 1 / There is an eachleft as well. / Are we having fun yet?? / More verbs! !8 / enumerate numbers from 0 up to (but not including) 8 #!8 3#!8 / "take" the first three number of this list 3_!8 / "drop" the first three numbers of this list -3#!8 / negative numbers to take from the back of the list -3_!8 9=3 / just plain equals. true is 1 and false is 0. 3=3 4=!6 / oho! scalar extension 0 1 2=!3 / and rank polymorphism! 0 1 2~!3 / match. i.e. check that the whole vector is the same (0;1 2 3)~(9=3;1+!3) / even for mixed vectors (0;1 2 3)=(9=3;1+!3) / rank polymorphism applies to ragged shapes as well. shapes must match (clearly) 3>4 / plain old greater than 3<4 ~3=3 / monadic ~ is not ~3>4 / less than or equal to is just not greater than. ~3>3 @7%3 / oh, yeah. floats are not ints _7%3 / floor strips off everything after the decimal point @_7%3 / .. and converts to ints _7 / floor of an int is fine -_-7%3 / There is no ceiling, but this emoji does the trick _"Hey, Dan!" / lower case for strings. (similar-ish..) %25 / monadic % is square root -35 / this is just an integer -(4 8 5) / this is the negate verb applied to a list -4 8 5 / this is just a list of integers -:4 8 5 / a colon forces this to be treated as a monadic function / Notice that this monadic function applies to each element of the list unlike length (#) / (colon has many more tricks up its sleeve...) |-:4 8 5 / this is that list reversed -4|8 / maximum of -4 and 8 (clearly no relation to the monadic reverse above) -4&8 / minimum of -4 and 8 ("abc";!3) / the "matrix" made of the rows "abc" and !3. / lists of lists of equal length can be thought of a matrices +("abc";!3) / flip! The transpose of that matrix. Again matrices must have rows of equal length. ("car";37;1 3 4)[0] / this long and no mention of array indexing?? ("car";37;1 3 4)[0 2] / indices can be lists ("car";37;1 3 4)[0 0] / lists can have repeats 1 4 9[2] / no need for explicit list notation 1 4 9[(0;2 1;(,1;0))] / more generally, indices can be any shape / the result matches the shape of the indices and picks out the values at the given index 1 4 9@(0;2 1;(,1;0)) / brackets are just syntactic sugar for the @ verb (called amend) 1 4 9[1 3] / outdexing results in a null ^1 4 9[1 3] / ^ tests for null 99^1 4 9[1 3] / With a value (atom/scalar) to the left fills all nulls with that value / More adverbs! +/3 5 9 / slash as an adverb is "left fold" with the accumulator starting as the first element. / Note here that the verb + is dyadic, but the derived verb +/ is used monadically 10+/3 5 9 / used dyadically, the left arg becomes the initial value for the accumulator / slashes used as comments must be preceded with a space / slashes used as adverbs must *not* be preceded by a space |/-4 8 5 / this is "max over". I.e. the fold of max over the list -4 8 5 |-4 8 5 / again, this is reverse |:-4 8 5 / this forces | to be read as its monadic form +\3 5 9 / the adverb scan is like fold, but produces all of its intermediate results 10+\3 5 9 / when using an explicit initial accumulator, the inital value is not part of the results +':9 4 2 / pairs up each element of its list with the prior element and applies the verb. ': is called each-next. / the first element is left as is 1+':9 4 2 / but you can supply a seed value to pair it with. 1-':9 4 2 / Note that the prior element becomes the right arg of the verb / There are a couple of funky adverbs which modify non-verbs, which we'll call nouns " "\"Yo yo yo" / Split takes a string and splits the argument it's given by it. / Actually here it's technically taking the *character* " ", but that works too "--"\"Yo--yo--yo" " "/("Hey"; "you") / Join takes an array of strings as its argument 10\12345 / Encode represents the given number as digits with the given base 2\13 10/9 8 7 / Decode calculates the value of a list of digits in the given base 2/1 0 1 1 0 1 24 60 60/1 2 3 / The base for each digit need not be the same / Note that because of how this works, the top base is irrelevant, but needed to match the number of digits -2 60 60/1 2 3 10 10\976 / For encode, if you supply a list of bases instead of a scalar, / you always get as many digits as the length of that list 2 2 2 2 2\5 0 2 2 2\134 / If the top base is zero, it just returns whatever is left over after decoding the other digits 2/0 2 2 2\134 / Back to verbs for a bit... 8#1 2 / Take can take more items than the list provided in which case it just cycles through 5#2 / You can even give take a scalar to simply repeat the value (5#2)\5 / Once again, parentheses are needed here because evaluation is from right-to-left 6 5#1 2 / You can even use a vector with take to generate lists of lists, one row at a time / In this case it's often called "reshape" but the idea is the same 2 5_!10 / Drop with a vector becomes "cut". The vector is split at the given indices and the first part is dropped. 0 3 7_!10 / To keep the first part, just make 0 the first element of the vector &0 0 1 0 1 1 / Given a boolean list, where (&) gives the indices of the 1's &1 0 2 3 0 4 / Actually, this is just a special case of "replicate" which generates a given number of repeats at the given index / Here there is 1 zero, no ones, two twos, three threes, etc. ?&1 0 2 3 0 4 / Monadic ? (distinct) only keeps the first occurence of each element in a list ? 7 8 2 3 7 1 3 7 8 2 3 7 1 3?1 / Dyadic ? (find) returns the index of the first occurence of the given element in a list 7 8 2 3 7 1 3?6 / If not found you get back a null / Now things get a little tricky.. / Some verbs behave differently when given different types of arguments. / This is kind of true with reshape and cut, but the behaviors weren't too different / So this next may seem a bit random ... 15?3 / Dyadic ? with an integer left argument is "roll". / It generates that many random numbers from 0 to the right argument 15?"ace" / If given a list as its right argument, it randomly picks elements from that list -5?5 / Deal is like roll only it doesn't repeat ?5 / As a monadic function ? returns values from a uniform distribution / Phew!! There's a lot here. Grab a hot tea and let some of this sink in a bit. / Feeling refreshed? Let's introduce a few more types... (1;"a";3%2) / so far, we've seen ints, chars and floats @'(1;"a";3%2) / with scalar types `i, `c and `f / Hmm... What is `i? @`i / A new type! `s represents the symbol type @`symbol / Symbols are basically scalar strings. In particular are used to represent types. @"symbol" / Remember vector types are represented with upper case letters. This is a vector of `c elements. #`symbol #"symbol" @`i`c`f / Vectors of symbols can be represented by listing them one after another / This is sometimes called "stranding". Stranding is only possible for homogenous types @1 2 3 5 / This is why vectors of integers can simply be listed one after another @(`i;`c;`f) / Of course explicit array notation is still possible @@'(1;"a";3%2) @'(1 2;"ab";3%2 1;`i`c) 1 0.3 2 / There is some magic here and there. Here the ints are "promoted" to floats 1 2 3+4 5 6 / Also, it's worth explicitly noting that stranding binds tighter than any of the verbs (1;2;3+4;5;6) / This is something different. 1 2,(3+4),5 6 / You could also make this by building it up with the verb concat. / The parentheses are necessary because of right to left evaluation @(1;"a";3%2) / Before we get too far away it's also worth noting that @ operates on the whole array / This is a single type known as a "mixed array" and is represented by `A @'(1;"a";3%2) / "each" is needed to operate on each element #'(1 2;"abcd";3%2 1;`i`c`s`A`C) / similar to length #(1 2;"abcd";3%2 1;`i`c`s`A`C) / Over time you get used to which functions do this and which ones "permeate". / i.e. operate on each element naturally like + or * / Let's introduce one more type: dictionaries `a`b`c!3 4 5 / Dictionaries act like association lists and created with dyadic ! operating on two lists of equal length !`a`b`c!3 4 5 / Monadic ! on a dictionary returns the keys of the dictionary .`a`b`c!3 4 5 / Monadic . on a dictionary returns the values of the dictionary (`a`b`c!3 4 5)[`b] / Indexing can be used to extract the value associated with a given key / It's probably best to start introducing some programming basics before moving on d:`a`b`c!3 4 5 / : is used for assigning to a variable (We told you colon had more tricks!) d / See? (This tutorial is running in a single session so this variable is still visible.) d[`b] / That looks nicer. We've extrated the value out of the dictionary d associated with the key `b / It may worth noting that variables are not symbols and not strings. They use no punctuation. i123:1 2 3 / You can use numbers in the name but initial character must be a letter i123[1] i123@1 / Remember that you can use @ to index into an array d@`c / Or even for looking up in a dictionary i123 1 / You can also just list the two next to each other! (This is *not* stranding!) d`c / You don't even need a space when it's not ambiguous i123: / Variables don't go away, but you can (re)assign them to "nothing" if you want to free memory i:1 2 3 / Different variable i 1 / Here we need a space because i1 would be a(n undefined!) variable name. d:`a`b`a!3 4 5 / Dictionaries can be weird. You can repeat keys. d`a / Only the first one is found with lookup (!d;.d) / But both original lists are still in the keys and values / BTW, there is no "iter". Keys and values must be extracted separately +(!d;.d) / Remember "flip"? This gets the list of key/value pairs (.d)(!d)?`a / This is basically what dictionary lookups do... (!d)?`a / This extracts the keys and then uses "find" to find the index of the key (.d)@(!d)?`a / This extracts the values and uses the previously found index to index into the array (.d)(!d)?`a / But because there's no ambiguity (really!) you don't need the @ here. It's not stranding so it's indexing. / The parentheses are needed because of right to left evaluation. / More programming basics ... and a new type! lambdas! f:{x} / Lambdas are formed with curly braces. This takes a single arg (x) and returns it. (f[1];f[`a];f[3%2]) / The lambda can be applied to arguments with brackets similar to array indexing (f@1;f@`a;f@3%2) / Or with @ .. (f 1;f`a;f 3%2) / Or even just juxtaposition .. f'(1;`a;3%2) / lambdas take adverbs just like verbs do {x+y}[2;3] / Brackets are (generally) necessary when supplying more than one arg f / Also, lambdas don't have to be assigned to a variable the way f was f:{x+y};f[1;2];f[3;4] / A semicolon can separate multiple statements on a line. Only the output of the last is printed f:{x+y};f[1;2]; / A trailing semicolon means the last statement was an "empty statement" and so nothing is printed {a:x+y;2*a}[1;3] / Multiple statements can of course be used inside a lambda as well / Kind of difficult to demonstrate in this format, but the semicolon can be replaced by a newline / only if the following line begins with at least one space. / E.g. {a:x+y / 2*a} / But this also means that the closing brace must be on the last line with a statement / In this example {a:x+y / 2*a / } / The last line is an empty statement and so prints nothing. {x*y+z}[2;3;4] / Functions can use up to three implicit arguments which have the names x, y and z f:{x+y}[2] / If fewer args are supplied than required, a "projection" is formed @'({x};{x+y}[2]) / Projections are actually a different type, but this doesn't come up that often f'3 4 5 / Projections basically "curry" the supplied argument {[a;b;c;d]a+b*c-d} / More than three arguments requires explicit argument declaration with brackets {[x;y]x+y}[2;3] / This can get noisy for simple stuff which is why implicit args exist {2*y}[1;3] / If you use an implicit y then the function takes (at least) two arguments, three if there is a z. {2*y}[7] / This is a projection {2*y}[7]@6 / When called, passes the argument to y f:+ / BTW, verbs can be assigned to variables too f[2;3] / But in this form must use bracket indexing instead of infix notation @f / Verbs have a different type as well @f:@ / Assignment can also happen inline. This assigns f and then takes its type. (@ is also a verb!) :[123;451] / Colon is also a (dyadic) verb which returns its second argument. / .. but is weird because it's hard to parse which of its various forms is meant in the code :i:1 2 3 / Here it's used monadically(??) to return the value assigned to i 123:456 / Here it's used dyadically to return the right argument :i:1 2 3 / This form is often useful when debugging code. @f:{x}' / Derived lambdas are yet another type f(1;"a";3%2;`b) g:+; 5 g/1 2 3 / Derived lambdas actually can be used infix g:+/; 5 g 1 2 3 / But only with explicit modifiers. This doesn't work. g:+; 5g/1 2 3 / Actually here the space before the g here is not necessary / What haven't we covered?... <"hello world" / grade! grade returns the indices in an order which sorts the input s@s / Actually that was grade up, grade down gives the indices which sort the other direction / One subtle point is that this is a "stable ordering" > 3 17 9 17 / i.e. indices which point to the same value remain in the same relative order < 3 17 9 17 / so grade down is not simply the reverse of grade up ::("a";98) / :: is the identity function but can be fiddly because of the many uses of : (::)"same" / Often it's safest to simply put it in parentheses :: / It has the unique property that when it's the final value on a line it prints nothing / Similarly, empty values are replaced with the identity iden:;iden "me" / Here iden is assigned an "empty" value, which simply means the identity function "happy"; / This amounts to the nitty gritty behind trailing semicolons inhibiting output ="hello world" / With a list = returns a dictionary / whose keys are the distinct elements and values are indices where that element occurs =5 / With a single integer = returns an identity matrix of that size {~x}_3 0 4 0 0 6 7 / _ becomes "weed out" with a left argument {~x}@3 0 4 0 0 6 7 / If we apply the function to the *whole* right argument we see which elements are removed (~:)_3 0 4 0 0 6 7 / We don't actually need a lambda, but a few extra considerations pop up without one / First we need to surround the verb with parentheses / to ensure that we're not trying to apply it / Technically this makes a *noun* out of the *verb* which is why it isn't applied / Also, we need to make sure that the function is applied monadically, so we use : (~:)@3 0 4 0 0 6 7 / Can still test to see which items will be removed / Here we need @ because its left arg is a noun. / This is all pretty heady. Mostly you just get used to the pattern. (~#:)@(,"I";"";"am") / Just to emphasize, the filter function is applied to the *whole* right arg (~#:')@(,"I";"";"am") / For length, which doesn't "permeate" like not, we'll need each (~#:')_(,"I";"";"am") / to filter out empty strings (~~#:')#(,"I";"";"am") / With # (replicate) you can specify which items to keep instead of to remove (3!)@1+!9 / Only replicate behaves differently when the function returns non-Booleans (3!)#1+!9 / In this case it replicates each value according to the corresponding integer &(3!)@1+!9 / This is just like where's (&) behavior, except where acts on indices l@&(3!)@l:1+!9 (3!)_1+!9 / Such replication doesn't make sense with weed out !4 3 / With a list on the right enumerate becomes "odometer". / Essentially cyclically count up the bottom row and "tick" each row / when the row beneath "turns over" +!4 3 / Alternatively, the transpose lists all possible "samples" of !:'(4;3) 4 3#+!4 3 / or lists all coordinates of a matrix of shape 4 3 / Coming round the final turn!! $(123;`happy) / Monadic $ stringifies its argument. Note this is pervasive. / i.e. that it converts at the element level and not the array level 4$$(123;`happy) / With an integer left argument limits to that length, padding on the right as necessary -4$$(123;`happy) / A negative number pads/chops on the left `s$"happy" / With a symbol on the left converts the right argument to that type when possible `s$123 / This errors when it's not possible `s$"@123=" / (Note you can make symbols of arbitrary strings by using quotes.) `c$104 97 112 112 121 `i$"happy" 0+"happy" / Characters actually naturally convert to ints when used in an int context. The value is the ASCII code. `I$"-123" / Use capital `I to convert the entire string to an integer rather than individual characters. / I/O! 1 1:"carpark" / with a left arg prints bytes to the left arg. Here 1 is the file descriptor for stdout `1:"carpark" / An empty symbol is equivalent to stdout / See help for other options including printing to a file `0:("happy";"dog") / 0: can take a list of strings as its right argument 1:1 / Without a left argument 1:reads bytes (buffered). 1 is the file descriptor for stdin. (type something followed by a return) / Same for 0: for reading lines, but is terminated by EOF. Tricker to demostrate here. `k@=5 / There are a handful of functions which are under symbols / `k is the basically the function used to render K objects in the REPL as strings `k'=5 / It accepts modifiers as well. Here we render each row of this identity matrix. `0:`k'=5 / It's useful in this tutorial to break out of the constraints of single line outputs. disp:`0:`k' disp@!4 3 disp@+!4 3 disp@4 3#+!4 3 ."3+5" / Monadic . with a string right value is "eval and evaluates the string as if it was run through the REPL. .`k@(1 2;"ab") / `k is designed to be "round-trippable". / I.e. evaluating the string generated by applying it to an argument should result in the argument. "HI, MOM"[1 4 5] / We talked about using brackets for indexing. "HI, MOM"@1 4 5 / Or alternately using the @ verb. @["HI, MOM";1 4 5] / You can even use bracket indexing with verbs. Including @ itself! / But @ is more powerful than your average verb... @["HI, MOM";1 4 5;_:] / With a third arg, replaces the values at that index with the (monadic) function applied to the corresponding value / Note that this returns the entire array modified at the given indices. @[!5;1 3 4;-;7 8 2] / With a fourth arg, does the same only using a dyadic function using the final argument as the right arguments @[!5;1 3 4;:;7 8 2] / A common use is with : as assignment @[!5;1 1;+;3 7] / Remember repeat indices are fine. @[!5;(1;,1);+;(3;,7)] / As are odd structures as long as the shapes match. / The function is applied at the leaves when descending the structure. disp @[=5;1 2] / Remembering that matrixes are lists of lists, @ simply picks out elements at that top-level list. disp m:4 3#!*/4 3 / But sometimes you want to dig deeper than the top-level list .[m;2 1] / Applied like this . becomes "drill", which picks out elements at the given coordinates disp.[m;2 1;-:] / Drill can also take a third argument disp.[m;2 1;*;3] / Or a fourth disp.[m;(3 1;0 2)] / Unlike @, when the second argument is a list, coordinates are generated by taking the Cartesian product disp 3 1,/:\:0 2 .[m;,3 1] / If this is a singleton list, this is the same as @ @[m;3 1] / Heavy stuff.. Let's finish off with a few more control structures. -2 ! 37 / Before that let's sneak in integer division. This is like modulo but with a negative modulus -2 2 !\: 37 / They're paired so that divmod can be calculated like so. / On to control structures... +\1+2*!10 / We've seen fold and scan which roll up values of a list with an accumulator. {x+y}\1+2*!10 / As a lambda it would look like this. Note that it takes two arguments and that the accumulator is the x argument {-2!x}\123678 / What if we tried a "scan" with a function which took only one argument? Like (integer) division by 2? / Instead of scan we get "converges". / I.e. the output gets fed back into the input and applied over and over until it stabilizes. -2!7 -2!3 -2!1 -2!0 -2!0 / So the difference between scan and converges is whether the function its being applied to takes two or one argument {-2!x}/123678 / There's also "converge" which doesn't produce intermediate results. (not as good for demonstration purposes, though.) {4!x+1}/1 / Actually converge also stops, when the input matches the original input. I.e. it detects complete cycles. / {4!x+1}/-1 / This on the other hand, never terminates, because while it cycles it never cycles back to the beginning. 10{4!x+1}\-1 / A left argument to converges isn't a seed. (That wouldn't make sense.) But if it's an integer, it's a repeat count. / i.e. similar to converges, but instead of detecting when to stop it does exactly that number of iterations. {~x=3}{4!x+1}\1 / With a function as a left argument, that function is evaluated with each iteration / and the process continues so long as that value is not zero. (::){4!x+3}\-1 / The function need not be a lambda. Here we use the identity function. {~x=3}{4!x+1}/1 / Of course there are versions of each of these which do not produce intermediate results / There's more we could talk about, but hopefully this is enough to get you started. / For more personal interaction, try one of the communities: [[https://k.miraheze.org/wiki/Online_Communities]] / Happy coding! / FIN