From bcf6abc50d705e80b532958d55107c073661ffa9 Mon Sep 17 00:00:00 2001
From: sforman There's an interesting video by Conor Hoekstra
+wherein he presents an example function implemented in BQN. It's the Sum of Squares of a list of numbers filtered by whether or not the index of each item in the list modulus the length of list. It's a weird thing to do, unlikely to come up in practice, but that's alright, it's just to exercise the language. I figure it might be fun and informative to derive a similar function in Joy (Thun). let's start with an example list on the stack: Following the BQN style, let's get the length ( We want to increment each index: But we will also want the length in a function that calculates an index Let's do both: Okay! Then Now we want to make these results into Booleans, but represented as integers (because we are going to multiply by them later): Clunky, but we now have our list of filter integers. Now, for each pair we want to multiply the pairs (using the duality of Booleans as integers to convert the numbers we want to work on to themselves and the numbers we do not want to work on to zero which is the --I don't recall the jargon!-- zero times anything is zero, and zero plus anything is that thing, and we use that in a moment to get around actually filtering our list!) As I was saying we multiply the pairs, then square the result, then sum all the results: Oops! I got the wrong result! I must have inverted the logic on the mapping to ints above: Hmm, that's not it. Maybe I'm indexing the items backwards? Ah! That was it. How do you like my debugging strategy here? Rather than reviewing the original to see that I was getting the right result at each step I just guessed at the "polarity" or "chirality" of the two operations that were (mildly, perhaps) ambiguous. It had to be one or the other, the function is too simple to hide many opportunities for confusion.) Let's examine this monster in all it's glory: Gnarly, eh? Let's reformat: Let's golf it a little. There is a version of Then: We can also collapse two of the We could extract sub-functions, e.g. But really, following the BQN style, this is about as good as it gets. That's BQN in Thun, what's it look like in Thun? One way to approach it is to simplify the desired function in terms of another function, and then to derive that other function. We know that the desired function is a "catamorphism" (roughly, it accepts a list and returns a single value) and we know that the "combining function" will be E.g.: So now the problem is to derive an efficient form of Let's assume for the moment that we have a function that gives us a predicate for the indicies: We run that on the list and then we can make something like this (where So: Except we need a counter for the index! How about a version of If the list is empty, it does nothing: But if the list has members it starts another function with an index counter initialized to zero. Since we know the list has at least one element we can set up the first evaluation of so Okay, so: And therefore: This function is like If the list has become empty, do nothing: If there are terms yet in the list it increments the counter and runs Where: Now then: Here's what we're trying to accomplish: It looks like we're done: I don't like it, but it should work (provided you write Various Jupyter notebooks, some more polished than others, a few incomplete.
-I'm in the process of rewriting them to use the Joy kernel.Nerd Sniped
+
+joy? [2 7 1 19 18 3]
+
+[2 7 1 19 18 3]
+size in Thun) and create a list of indicies:
+[2 7 1 19 18 3]
+
+joy? dup size range
+
+[2 7 1 19 18 3] [5 4 3 2 1 0]
+
+[2 7 1 19 18 3] [5 4 3 2 1 0]
+
+joy? [++] map
+
+[2 7 1 19 18 3] [6 5 4 3 2 1]
+mod the length:
+[2 7 1 19 18 3]
+
+joy? dup size [swap mod] cons
+
+[2 7 1 19 18 3] [6 swap mod]
+
+joy? clear [2 7 1 19 18 3]
+
+[2 7 1 19 18 3]
+
+joy? dup size [range [++] map] [[swap mod] cons] cleave
+
+[2 7 1 19 18 3] [6 5 4 3 2 1] [6 swap mod]
+map the one over the other:
+joy? map
+
+[2 7 1 19 18 3] [0 1 2 0 0 0]
+
+[2 7 1 19 18 3] [0 1 2 0 0 0]
+
+joy? [0 = [0] [1] branch] map
+
+[2 7 1 19 18 3] [1 0 0 1 1 1]
+zip to transpose the two lists to a list of pairs:
+[2 7 1 19 18 3] [1 0 0 1 1 1]
+
+joy? zip
+
+[[1 2] [0 7] [0 1] [1 19] [1 18] [1 3]]
+
+[[1 2] [0 7] [0 1] [1 19] [1 18] [1 3]]
+
+joy? [i * sqr] map
+
+[4 0 0 361 324 9]
+
+joy? sum
+
+698
+
+[2 7 1 19 18 3] [0 1 2 0 0 0]
+
+joy? [0 = [1] [0] branch] map
+
+[2 7 1 19 18 3] [0 1 1 0 0 0]
+
+joy? zip
+
+[[0 2] [1 7] [1 1] [0 19] [0 18] [0 3]]
+
+joy? [i * sqr] map
+
+[0 49 1 0 0 0]
+
+joy? sum
+
+50
+
+[2 7 1 19 18 3] [0 1 2 0 0 0]
+
+joy? reverse
+
+[2 7 1 19 18 3] [0 0 0 2 1 0]
+
+joy? [0 = [0] [1] branch] map
+
+[2 7 1 19 18 3] [1 1 1 0 0 1]
+
+joy? zip
+
+[[1 2] [1 7] [1 1] [0 19] [0 18] [1 3]]
+
+joy? [i * sqr] map
+
+[4 49 1 0 0 9]
+
+joy? sum
+
+63
+
+dup size [range [++] map] [[swap mod] cons] cleave map reverse [0 = [0] [1] branch] map zip [i * sqr] map sum
+
+dup size
+[range [++] map] [[swap mod] cons] cleave
+map
+reverse
+[0 = [0] [1] branch] map
+zip
+[i * sqr] map
+sum
+≡
+reverse-range-++range that generates its result list in reverse order, which would allow us to get rid of that reverse in the expression, and I bet we could modify that to generate them already incremented too. Let's assume we've done that already and call it reverse-range-++, why not?
+[reverse-range-++ range [++] map reverse] inscribe
+
+dup size
+[reverse-range-++] [[swap mod] cons] cleave
+map
+[0 = [0] [1] branch] map
+zip
+[i * sqr] map
+sum
+map functions into one:
+dup size
+[reverse-range-++] [[swap mod 0 = [0] [1] branch] cons] cleave
+map
+zip
+[i * sqr] map
+sum
+[0] [1] branch converts Booleans to integers, we might wind up using that again somewhere, eh?What's it Look Like in Thun?
+sqr + with some filter. So let's start with a specialization of step:
+0 swap [sqr +] step-indicies-mod-length
+
+0 [2 7 1 19 18 3] [sqr +] step-indicies-mod-length
+step-indicies-mod-length
+size [swap mod 0 =] cons
+n is the size of the list):
+n swap mod 0 = [pop] [sqr +] branch
+
+0 [2 7 1 19 18 3] [F] step
+≡
+step-enumeratestep that also enumerates the list items?
+[...] [F] step-enumerate
+
+ [] [F] step-enumerate
+---------------------------
+F:
+ [a ...] [F] step-enumerate
+---------------------------------------
+ a 0 F [...] [F] 0 step-enumerate′
+
+step-enumerate == over truthy [popop] [FOO] branch
+FOO
+[a ...] [F] FOO
+[a ...] [F] [uncons] dip
+a [...] [F] 0 roll<
+a 0 [...] [F] dupdipd
+a 0 F [...] [F] 0 step-enumerate′
+
+FOO == [uncons] dip 0 roll< dupdipd 0 step-enumerate′
+
+[step-enumerate over truthy [popop] [[uncons] dip 0 roll< dupdipd 0 step-enumerate′] branch] inscribe
+step but it first increments the counter before each evaluation of F.
+ ... [] [F] n step-enumerate′
+----------------------------------
+F with (a copy of) it:
+ ... [b ...] [F] n step-enumerate′
+---------------------------------------------------
+ ... b (n+1) F [...] [F] (n+1) step-enumerate′
+A simple General Recursive Function
+
+ ... [] [F] n step-enumerate′
+ -------------------------------------------
+ ... [] [F] n [P] [T] [R0] [R1] genrec
+---------------------------------------------------------
+ ... [] [F] n [P] [T] [R0 [step-enumerate′] R1] ifte
+
+P == popop not
+
+E == popopop
+
+... [b ...] [F] n R0 [step-enumerate′] R1
+
+ ... [b ...] [F] n R0 [step-enumerate′] R1
+ ... b (n+1) F [...] [F] (n+1) step-enumerate′
+R1 is trivially i (so this is a tailrec function.) Let's derive R0:
+... [b ...] [F] n R0
+... [b ...] [F] n ++
+... [b ...] [F] (n+1)
+
+... [b ...] [F] (n+1) [swons] nullary
+... [b ...] [F] (n+1) [(n+1) F]
+- - - - -
+
+... [b ...] [F] (n+1)
+... [b ...] [F] (n+1) [uncons] dipd
+... [b ...] uncons [F] (n+1)
+... b [...] [F] (n+1)
+
+... b [...] [F] (n+1) [swons] nullary
+... b [...] [F] (n+1) [(n+1) F] dipddd
+... b (n+1) F [...] [F] (n+1)
+
+R0 == ++ [uncons] dipd [swons] nullary dipddd
+dipddd, eh?)Notebooks
+Thun Notebooks
+