> If you go to the link and press 'help' you'll see some docs for ngn/k

Almost as impenetrable as the code unless you already know the language. But that's ok - I guess that's the main audience...

E.g. trying to figure out what "\" means, in that help is only easier now because you gave me the whole line, as there are 64 occurrences of "\" in that doc and I wouldn't have known what pattern to search for to limit it...

It's back to the philosophical disconnect of expecting people to read start to finish/know far more detail inside out rather than skimming and relying on easy keyword lookups... (yes, we're lazy)

> 'reduce with concat'

So "flatten" in Ruby-speak, I take it (though "flatten" without an argument in Ruby will do this recursively, so I guess probably flatten(1) would be a more direct match).

> you don't need to do any mapping, it's automatic.

After these pointers (thanks!), here's - mostly for my own learning, what I ended up with not in an attempt to get closer to the linenoise (we can do that with a horrific level of operator overloading that'd break most of the standard library, though we can't match k precisely). Please don't feel obliged to go through this unless you're morbidly curious; I just had to, but I'm sure you'd suffer going through my attempt at figuring out what the hell k is doing...:

textb="What hath the Flying Spaghetti Monster wrought?"

# Firstly, I finally realised after a bunch of testing that 1) "(8#2)" does something like this.
# That is, the result of 8#2 is (2 2 2 2 2 2 2 2), which was totally not what I expected.
def reshape(len,items) = [].fill(0...x)

class Integer
# For the special case of (x#y) where x is a positive integer, which is frankly the only one
# I've looked at, we can do:
# So now 4.reshape(2) returns [2 2 2 2] just like (4#2) in ngn/k
def reshape(items) = Array(items)*self

# Now we can do something somewhat like what I think "encode" is
# actually doing - this can be golfed down, but anyway:
# With this, "a".ord.encode(8.reshape(2)) returns [0,1,1,0,0,0,0,1],
# equivalent to (8#2)\ "a" in ngn\k
def encode(shape)
rem = self
Array(shape).reverse.map do |v|
val = rem % v
rem = rem / v
val
end.reverse
end
end

# Now we can break Array too.
class Array
# First a minor concession to how Ruby methods even on the Array
# class sees the focal point as the Array rather than the elements.
# E.g. `self` in #map is the Array. If the focus is to be on applying the
# same operation to each element, then it might be more convenient
# if `self` was the element. With this, we can do ary.amap{reverse}
# instead of ary.map{|e| e.reverse} or ary.map{ _1.reverse}.
# To get closer to k, we'd have needed a postfix operator that we could
# override to take a block, but unfortunately there are no overridable
# postfix operators in Ruby. E.g. we can hackily make
# ary.>>(some_dummy_value) {a block} work, but not even
# ary >> (some_dummy_value) { a block} and certainly not
# ary >> { a block }
#
def amap(&block) = map { _1.instance_eval(&block) }

# If we could do a "nice" operator based map, we'd just have left it
# at that. But to smooth over the lack of one, we can forward some
# methods to amap:
def encode(...) = amap{encode(...)}
# ... with the caveat that I realised afterwards that this is almost certainly
# horribly wrong, in that I think the k "encode" applies each step of the
# above to each element of the array and returns a list of *columns*.
# I haven't tried to replicate that, as it breaks my mind to think about
# operating on it that way. That is, [65,70].encode(2.reshape(10))
# really ought to return [[6,7],[5,0]] to match the k, but it returns
# [[6,5],[7,0]]. Maybe the k result will make more sense to me if I
# take a look at how encode is implemented...

def mreverse = amap{reverse}
end

# Now we can finally get back to the original, with the caveat that due to
# the encode() difference, the "mreverse.flatten(1)" step is in actuality
# working quite differently, in that for starters it's not transposing the arrays.
#
p textb.bytes.encode(8.reshape(2)).mreverse.flatten(1)

# So to sum up:
#
# textb -> textb.bytes since strings and byte arrays are distinct in Ruby
# (8#2) -> 8.reshape(2)
# x\y -> y.encode(x) ... but transposed.
# |x -> x.mreverse
# ,/+x -> x.flatten(1) .. but really should be x.transpose.flatten(1)
#
# Of course with a hell of a lot of type combinations and other cases the k
# verbs supports that I haven't tried to copy.