Frantically tried to crack this and write it up so I could squeeze this into the month just because of the alliteration and failed.
I’m not sure now how I ended up playing with Joy, but I think it was because I had Forth on my learning list and Joy was mentioned there.
It is a wee bit confusing.
You provide the arguments for a function and then the function and execute it by finishing with a period (like Erlang). So to add two numbers:
2 3 +.
Ok, so that isn’t confusing, but if you want to add the result of that sum to the result of another sum, say (2 + 3) + (4 + 5) you end up with the following:
2 3 + 4 5 + +.
It starts to get confusing. You have to mentally visualise the brackets.
There are no variables and you can’t build up intermediate results (as far as I know) to make things easier to read, you’ve got to do everything in one go. You can however use DEFINE blocks (like Erlang) to build up functions, etc up-front.
I thought I’d start with very simple programme since my poor little brain was (still is) struggling a bit to wrap itself around Joy: Given two lists of gears/sprockets (for my bike) calculate all the ratios and sort them, displaying both the ratio and the gear pairs. So if I input something like so:
DEFINE
littlegears == [12 13 15 17 19 21 23 25];
biggears == [34 50].
I can get an output like so:
[ [ 4.1667 "50/12"] [ 3.846 "50/13"] ... and so on ]
Calculating ratios
First step was calculating all the ratios. My first attempt was as follows:
littlegears [biggears 1 at 1.0 * /] map [-1 pow] map
littlegears [biggears 0 at 1.0 * /] map [-1 pow] map
concat.
which is tricky to understand already. The first line calculates all the ratios against the 50 and the second against 34 and both these lists are then joined together with concat
. Looking at just the first line, the “50” value is obtained by biggears 1 at
which leaves:
littlegears [50 1.0 * /] map [-1 pow] map
This is then multiplied by 1.0 so it’s converted to a float from an integer, which is important when it comes to dividing.
littlegears [50.0 /] map [-1 pow] map
The first map
then takes the 50.0
and the divide and applies this over the littlegears
list so you end up with:
[0.24 0.26 0.3 0.34 0.38 0.42 0.46 0.52] [-1 pow] map
The problem with mapping the 50 /
over the list is that my divisions are inverted. I don’t want to divide the little gears by the big gears I want it the other way round. My cludgy fix for this was to raise all values to the power of minus one, effectively inverting them.
I thought there must be a better way to do this, like Haskell’s flip
function. And there is:
littlegears [50.0 swap /] map.
does the same as:
littlegears [50.0 /] map [-1 pow] map
Merging Two lists as pairs
Ok, so I know how to get all the ratios, but that is not much use on it’s own. The next thing I wanted to figure out was how to merge two lists by grouping as pairs so I could have the ratios next to the gear combinations ([ [4.1667 "50/12"] ... ]
). I started playing about a list containing two little lists:
[[1 2] [3 4]]
And trying to get this result:
[[1 3] [2 4]]
In Joy cons
is the function use to join an element to a list so the following did the trick, but only for a two element list:
[[1 2] [3 4]] [first] map
[[1 2] [3 4]] [second] map
[] cons cons.
For a three element list I’d need:
[[1 2 3] [4 5 6]] [first] map
[[1 2 3] [4 5 6]] [second] map
[[1 2 3] [4 5 6]] [third] map
[] cons cons cons.
And so on which isn’t very sustainable for longer lists. I’m currently stuck on how to do this bit properly. I can’t find any function in the documentation that takes two lists (aggregates) so I don’t think I’m missing an easy way to do this.
Getting list of gear pairs
I couldn’t find any function to format an integer as a string. There are string to integer and string to float functions, but not the reverse as far as I can tell. So I thought I would build the results as follows: [ [ 4.1667 50 12] ... etc ]
sorted on ratio.
littlegears [ [30] cons] map.
builds up the gear pairs, although the gears are listed the wrong way:
[[12 30] [13 30] [15 30] [17 30] [19 30] [21 30] [23 30] [26 30]]
If I want them the right way round it gets messier:
littlegears [ [] cons ] map [ [30] swap concat] map.
Sorting a nested list
The tutorial has an implementation of quick sort which is meant to be in the standard library - it’s not in what I’ve compiled - and I’ve tried adapting that to work on a nested list:
[[7 4] [3 5] [6 9] [1 3]]
As follows:
[small]
[]
[uncons [first >] split]
[[swap] dip cons concat]
binrec
So I get:
[[1 3] [3 5] [6 9] [7 4]]
But it doesn’t work.
And so that’s where I’m up to so far. No answers on postcards please - I’m sure I’ll figure it out sooner or later.