|
@@ -0,0 +1,390 @@
|
|
|
|
+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:"hello world" / (Remember we can do assignment inline)
|
|
|
|
+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
|