-
Notifications
You must be signed in to change notification settings - Fork 11
/
sect_logic.xxl
133 lines (97 loc) · 5.71 KB
/
sect_logic.xxl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// note for human readers: this doc is meant to be consumed by XXL itself to
// produce the documentation website. the markdown tags below with triple
// quotes are code samples. the part before the ||| is the XXL code
// and the part after it is the result.
"
Like other languages, XXL has a set of verbs for conditional logic, like the
\"if\" and \"else\" statements that we're all used to. I believe ours are more
powerful, and more regular, than most.
We'll be using these verbs in this section. You may want to review them.
`verbsummary:match,rot,condense,amend`
Most of XXL's logic verbs work with vectors of bytes, composed of 0s and 1s.
For example:
```"hello world"~"o"|||(0,0,0,0,1,0,0,1,0,0,0)```.
`~` is match. Match checks every item in the left argument against the item
in the right argument, which can be a specific value (like `"o"`) or a
function.
The result is a list of 0s where the value wasn't found (or where the
function returned something "falsey"), and 1s where it was found (or
the function returned something "truthy").
Why not just return the indices, instead of a vector of booleans?
This is useful because you can compose these boolean lists together to form
more complex logic, in ways that are often difficult to state in other
languages.
To start with a very simple example, which doesn't require too many interesting
logical conditions, let's say you wanted to write a function to upper case the
first letter of every word in a sentence. In PHP this is known as ucwords() and
it's one of those helper functions that you always seem to need when running
some horrible errand.
We already saw your first stab at something similar:
```"hello world"~"o"|||(0,0,0,0,1,0,0,1,0,0,0)```.
Just for fun as we start exploring this problem, let's get the positions of all
the spaces:
```"hello world"~" "|||(0,0,0,0,0,1,0,0,0,0,0)```.
OK, so we need to capitalize the letter *after* those spaces. So let's rotate
that vector by negative one which is equivalent to shifting everything to the
right (i.e., move the 1 right after the space, where the "w" is):
```"hello world"~" "rot(1neg)|||(0,0,0,0,0,0,1,0,0,0,0)```.
We also need the first character of course, so we'll set position zero to 1
using the `amend` verb. `amend` takes an argument on its left as x and modifies
it according to y, which is in the format [indices_to_update, new_values].
It's often (rightly) abbreviated as `!`, but we'll use the full name here.
```'up is {x-" "}; "hello world" as 'str ~ " "rot(1neg) amend [0,1]|||(1,0,0,0,0,0,1,0,0,0,0)```
OK, this list looks right. Now we have to modify the characters we've identified and make them
upper case.
Most languages have some kind of handy toupper or uppercase function, but we
don't have that yet in XXL. So we'll just use our knowledge of ASCII and
subtract 32 from the value of that character. Let's make a little function so
we can test our idea to be sure our memory of the arcane is working properly:
```'up is {x-32}; "dog" up|||(68,79,71)```
Well, those ASCII codes look right, but it's no longer a string! Never fear.
Plus (and the other math operators), when faced with two different kinds of
number vectors (in this instance, a char vector (string, 8 bits per character) and an
integer (32 bits per number)) try to produce the result as the "bigger type" of the two.
That way you won't have to worry as much about numbers overflowing the types they are
stored in. In this case, though, major annoyance.
Let's fix this using a handy built in verb called `make`, which transforms vectors
from one similar type to another. You supply your original value as x and the type
you want to convert to as a name (tag) in the y parameter. In this case, we want
to use `'char`.
```'up is {x-32 make 'char}; "dog" up|||"DOG"```
For extra points, use your ninja-level knowledge of computer internals to
recall the fact that the space character just so happens to be character number
32, and skip the `make` step altogether, by subtracting the char directly!
```'up is {x-" "}; "dog" up|||"DOG"```
(If this was something you'd really be adding to your little toolbox, you should
check to be sure the character is within the range of lowercase characters
before adjusting it.)
Pretty cute expression but we're not quite ready to collect our Turing award
just yet. All we have yet to do is update the original string with our new function
applied in the indices we've discovered.
Thinking back, recall that the `amend` function (optionally known by its operator,
`!`) can be used to update single values inside a vector. This sounds exactly
like what we want to do!
Remember that `amend` expects a list of indices to update, and what we have is a
boolean list of 0s and 1s, denoting the true/false value of our test against each
of those values. We're done with using it in that format so to convert it to a list
of indices, use `condense`:
```"hello world"~" "rot(1neg) amend [0,1] condense|||(0,6)```
Alright, now for the amend bit. This shouldn't be too hard. Since our expression
is getting a little longer, I'm going to save parts of it as named values
(variables) using `as`. Then we can refer to bits and pieces of it as we build
our final expression:
```{x-" "} as 'up;
"hello world" as 'str
~" " rot (1neg) amend [0,1] condense as 'where;
str amend [where,up]
|||"Hello World"```
It works! Have a martini to celebrate.
There's something to be said for brevity if applied with a modicum of taste. Later on,
once you're drunk, consider the shortest way to write this expression. I think
it's:
```"hello world"as 's![(s~" "rot(1neg)![0,1]~>),{-" "}]```
Another version, using the lurid `aside` verb, might be:
```"hello world"aside{~" "rot(1neg)![0,1]~>as 'w}![w,{-" "}]```
For more information, see the following verbs:
`{verbsincat:'logic}`
"