summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorNicholas Georgescu <36280690+NGeorgescu@users.noreply.github.com>2024-05-13 15:10:46 -0400
committerGitHub <noreply@github.com>2024-05-13 13:10:46 -0600
commit154d5272a01e68ec1e0871d75d94fc7bf8a871e0 (patch)
tree827d129efdba49ee69d3587ac5bcff6c3d5cf796
parentc3f67d32c8dfd16a08662b8301686f7335a83823 (diff)
[GolfScript/en] (#4626)
-rw-r--r--golfscript.html.markdown619
1 files changed, 619 insertions, 0 deletions
diff --git a/golfscript.html.markdown b/golfscript.html.markdown
new file mode 100644
index 00000000..8ea985e8
--- /dev/null
+++ b/golfscript.html.markdown
@@ -0,0 +1,619 @@
+---
+language: GolfScript
+filename: golfscript.gs
+contributors:
+ - ["Nicholas S Georgescu", "http://github.com/ngeorgescu"]
+---
+
+GolfScript is an esoteric language that was developed in 2007 by Darren
+Smith. It is a scripting language with an interpreter written in Ruby. It lets
+you write very dense code in very few characters. The main goal of the language
+is, as the name suggests, to solve problems in as few keystrokes as possible.
+The examples page on the GolfScript website even has an entire Sudoku solver
+written in just 77 characters.
+
+If you get really good at GolfScript you can easily find yourself using it as a
+go-to language for solving some (even somewhat hard) coding problems. It's never
+going to be faster than Ruby, but it can be very fast to write, since a single
+character of GolfScript can replace an entire line of code in some other languages.
+
+GolfScript is based on the use of the stack. This tutorial therefore will
+read as a sequence of stack operations on an actual stack, as opposed to some
+standalone code and individual results. The stack starts as an empty list, and
+everything either adds to the stack, or it pops some items off, transforms them,
+and puts them back onto the stack.
+
+To get started running GolfScript, you can get the golfscript.rb file from the
+[GitHub repo](https://github.com/darrenks/golfscript). Copy it into your `$PATH`,
+(dropping the .rb and chmodding as necessary). You can run GolfScript from either
+the interactive interpreter (which mirrors the tutorial below). Once you get the hang
+of GolfScript, you can start running from "stdin". If you see a script starting with `~`,
+it was probably designed to be dropped in a file and run with `golfscript file.gs`. You
+can pipe in or enter in your input at runtime.
+
+```golfscript
+> anything undefined technically evaluates to nothing and so is also a comment
+# but commenting it out explicitly anyway is probably a good idea because if
+# you use a reserved keyword or any punctuation you'll run into trouble.
+[]
+> ######################################################################
+# datatypes
+########################################################################
+> 1 # Here we add 1 to the stack. Any object entry adds things to the stack
+[1]
+> 'abc' # here we are adding a string. The only difference between single and
+# double quotes is that double lets you escape more things other than \' and \n
+# it won't matter for the sake of this tutorial.
+[1 "abc"]
+> {+} # the third type of object you can put on the stack is a block
+[1 "abc" {+}]
+> ] # this takes everything prior and puts it into an array, the fourth type
+# of object. (besides bug exploits like [2-1?] those are the only four types)
+[[1 "abc" {+}]]
+> ; # let's clear the stack by executing the discard function on this array.
+# if you type the characters ]; it always clears the stack.
+[]
+> 1"abc"{+}]; # newlines are whitespaces. Everything we did up to this point
+# can be put into one line and it all works the exact same.
+########################################################################
+# operators and math
+########################################################################
+[]
+> 1 1 # we add two 1s to the stack. We could also duplicate the first with .
+[1 1]
+> + # math is done by executing an operation on the top of the stack. This
+# can be a standalone character. The way to read this is that we put a 1 on
+# the stack, another one one the stack, and then executed a + operation which
+# takes the top two elements off of the stack, sums them up, and returns them
+# to the stack. This is typically referred to as postfix notation. It can be
+# a bit jarring, but this is the way to think about things. You're adding to
+# the stack with objects and modifying the top of the stack with operators.
+[2]
+> 8 1- # minus works the same way. N.B. that we still have that 2 on the stack
+# from earlier
+[2 7]
+> 10 2* # multiplication works the same way. The product is added to the stack
+[2 7 20]
+> 35 4/ # all division is integer division
+[2 7 20 8]
+> 35 4% # modulo operation
+[2 7 20 8 3]
+> 2 3? # exponentiation
+[2 7 20 8 3 8]
+> 8~ # bitwise "not" function on signed integers
+[2 7 20 8 3 8 -9]
+> -1~ # this yields 0, which is useful to know for the ? operator
+[2 7 20 8 3 8 -9 0]
+> 5 3| # or: yields 7, since [1 0 1] | [0 1 1] => [1 1 1]
+[2 7 20 8 3 8 -9 0 7]
+> 5 3^ # xor: yields 6, since the parity differs at [1 1 0]
+[2 7 20 8 3 8 -9 0 7 6]
+> 5 3& # and: yields 1, since it's the only bit active in both: [0 0 1]
+[2 7 20 8 3 8 -9 0 7 6 1]
+> ]; ###################################################################
+# booleans
+########################################################################
+[]
+> 5 3
+[5 3]
+> < #add two numbers to the stack, and then perform a lessthan operation
+# booleans are False if 0, [], {}, '', and true if anything else.
+[0]
+> 5 3> # greater than operation.
+[0 1]
+> 5 3= #single equal is the operator. Again, before the equals is executed,
+# the stack reads [0 1 5 3], and then the equals operator checks the top 2
+# values and yields:
+[0 1 0]
+> ! #not, returns 1 if 0 else 0.
+[0 1 1]
+> ) #increments the last number
+[0 1 2]
+> ( #decrements the last number
+[0 1 1]
+> ]; ###################################################################
+# stack control
+########################################################################
+[]
+> 1 # put a number on the stack
+[1]
+> . # duplicate the number
+[1 1]
+> ) # increment
+[1 2]
+> \ # flip the top two items
+[2 1]
+> 1$ # $ copies the nth-to-last item on the stack at the index preceding.
+# Here we get the 1-indexed item.
+[2 1 2]
+> 0$ # to copy the 0-indexed item we use the appropriate index.
+# This is identical to . operation
+[2 1 2 2]
+> ) # increment
+[2 1 2 3]
+> @ # pulls the third item up to the top
+[2 2 3 1]
+> [@] # use this trick to flip the top 3 items and put them into an array
+# if you wrap any operation in brackets it flips the results into an array.
+# even math operations like, [+] and [-]
+[2 [3 1 2]]
+> ]; # also, using at most two strokes you can orient the top three items
+# in any permutation. Below are shown the results on 3,~
+ # => 0 1 2 (i.e. doing nothing)
+ # \ => 0 2 1
+ # @\ => 1 0 2
+ # @ => 1 2 0
+ # @@ => 2 0 1
+ # \@ => 2 1 0
+[]
+> ######################################################################
+# using arrays
+########################################################################
+[]
+> 2, # comma is the range() function
+[[0 1]]
+> , # and also the length() function
+[2]
+> ;4, # let's get an array of four items together
+[[0 1 2 3]]
+> ) # we can pop off the last value
+[[0 1 2] 3]
+> + # and put it back
+[[0 1 2 3]]
+> ( # we can pop off the first value
+[[1 2 3] 0]
+> \+ # and put it back
+[[0 1 2 3]]
+> 2- # we can subtract a particular value
+[[0 1 3]]
+> [1 3] # or a list of values
+[[0 1 3] [1 3]]
+> -
+[[0]]
+> ! # boolean operations also work on lists, strings, and blocks. If it's
+# empty it's a 1, otherwise 0. Here, the list has a zero, but it's not zero-
+# length, so the array as a whole is still True... and hence "not" is False
+[0]
+> ;4,(+ # let's make a range, pop the first value, and tack it on the end
+[[1 2 3 0]]
+> $ # we can also restore order by sorting the array
+[[0 1 2 3]]
+> 1 > # we can also use < > and = to get the indeces that match. Note this
+# is not a filter! This is an index match. Filtering items greater than one
+# is done with {1>},
+[[1 2 3]]
+> 2 < # remember it's zero-indexed, so everything in this array is at an index
+# less than 2, the indeces are 0 and 1.
+[[1 2]]
+> 1= # < and > return an array, even if it's one item. Equals always drops
+# it out of the array
+[2]
+> ;6,2% # the modulo operator works on lists as the step.
+[[0 2 4]]
+> ;4,2,-:a 3,2+:b # booleans also work on lists. lets define two lists
+[[2 3] [0 1 2 2]]
+> | # "or" - returns set of items that appear in either list i.e. "union set"
+[[2 3 0 1]]
+> ;a b& # returns set of items that appear in 1 AND 2, e.g. "intersection set"
+[[2]]
+> ;a b^ # returns the symmetric difference set between two lists,
+[[3 0 1]]
+> ~ # tilde unpacks the items from a list
+[3 0 1]
+> ]; a
+[2 3]
+> 2? # finds the index of an item
+[0]
+> ;3a?
+[1]
+> 4a? # returns -1 if the item doesn't exist. Note: Order of element and array
+# doesn't matter for searching. it can be [item list?] or [list item?].
+[1 -1]
+> ]; # clear
+[]
+> 3,[4]* # join or intersperse: puts items in between the items
+[[0 4 1 4 2]]
+> ; 3,4* # multiplication of lists
+[[0 1 2 0 1 2 0 1 2 0 1 2]]
+> ;[1 2 3 2 3 5][2 3]/ # "split at"
+[[[1] [] [5]]]
+> ;[1 2 3 2 3 5][2 3]% # modulo is "split at... and drop empty"
+[[[1] [5]]]
+> ];####################################################################
+# strings
+########################################################################
+# strings work just like arrays
+[]
+> "use arch, am vegan, drive a stick" ', '/ # split
+[["use arch" "am vegan" "drive a stick"]]
+> {'I '\+', BTW.'+}% # map
+[["I use arch, BTW." "I am vegan, BTW." "I drive a stick, BTW."]]
+> n* # join. Note the variable n is defined as a newline char by default
+["I use arch, BTW.\nI am vegan, BTW.\nI drive a stick, BTW."]
+> n/ # to replace, use split, and join with the replacement string.
+[n "Also, not sure if I mentioned this, but" n]{+}* # fold sum 3-item array
+* # and use join to get the result
+n+ print # and then pop/print the results prettily
+I use arch, BTW.
+Also, not sure if I mentioned this, but
+I am vegan, BTW.
+Also, not sure if I mentioned this, but
+I drive a stick, BTW.
+[]
+> '22222'{+}* # note that if you fold-sum a string not in an array, you'll
+# get the sum of the ascii values. '2' is 50, so five times that is:
+250
+> ]; ###################################################################
+# blocks
+########################################################################
+[]
+> 3,~ # start with an unpacked array
+[0 1 2]
+> {+-} # brackets define a block which can comprise multiple functions
+[0 1 2 {+-}]
+> ~ # blocks are functions waiting for execution. tilde does a single
+# execution of the block in this case, we added the top two values, 1 and 2,
+# and subtracted from 0
+[-3]
+> ;10,~{+}5* # multiplication works on executing blocks multiple times
+# in this case we added the last 6 values together by running "add" 5 times
+[0 1 2 3 39]
+> ];10,4> # we can achieve the same result by just grabbing the last 6 items
+[[4 5 6 7 8 9]]
+> {+}* # and using the "fold" function for addition.
+[39]
+> # "fold" sequentially applies the operation pairwise from the left
+# and then dumps the results. Watch what happens when we use the duplicate
+# operator to fold. it's clear what happens when we duplicate and then negate
+# the duplicated item:
+> ;4,{.-1*}*
+[0 1 -1 2 -2 3 -3]
+> ]{3%}, # we can filter a list based on applying the block to each element
+# in this case we get the numbers that do NOT give 0 mod 3
+[[1 -1 2 -2]]
+> ;10,{3%0}, # note that only the last element matters for retaining in the
+# array. Here we take 0..9, calculate x mod 3, and then return a 0. The
+# intermediate generated values are dumped out sequentially.
+[0 1 2 0 1 2 0 1 2 0 []]
+> ]; # clear
+[]
+> 5,{5*}% # map performs each operation on the array and returns the result
+# to an array
+[[0 5 10 15 20]]
+> {.}% # watch what happens when you map duplicate on each item
+[[0 0 5 5 10 10 15 15 20 20]]
+> ]; ###################################################################
+# Control Flow!
+########################################################################
+# This is the most important part of scripting. Most languages have
+# two main types of loops, for loops and while loops. Even though golfscript
+# has many possible loops, only a few are generally useful and terse. For loops
+# are implemented using mapping, filtering, folding, and sorting over lists.
+# For instance, we can take the factorial of 6 by:
+6, # get 0..5
+{)}% # increment the list, i.e. "i++ for i in list" to get 1..6
+{*}* # fold by multiplication , 9 characters for the operator itself.
+[720]
+> 6),(;{*}* # but can we get shorter? We can save some space by incrementing
+# the 6, dropping the zero, and folding. 8 characters.
+> # we can also use fold to do the same thing with unfold
+1 6 # accumlator and multiplicand, we'll call A and M
+{}{ # while M
+ . # copy M, so now the stack is A M M
+ @ # bring A to the top, so now M M A
+ * # apply M to the accumulator, so M A
+ \( # flip the order, so it's A M, and M--
+}/; # "end", drop the list of multiplicands
+# this is effectively a while-loop factorial
+[720 720]
+> 1.{6>!}{.@*\)}/; # we can also do the same thing with M++ while M not > 6
+> 1 6{.@*\(.}do; # works the same way as the decrementing fold.
+[720 720 720]
+> ]; #obviously a for loop is ideal for factorials, since it naturally lends
+# itself to running over a finite set of items.
+########################################################################
+# Writing code
+########################################################################
+# Let's go through the process for writing a script. There are some tricks and
+# ways to think about things. Let's take a simple example: a prime sieve.
+# There are a few strategies for sieving. First, there's a strategy that
+# uses two lists, candidates and primes. We pop a value from candidates,
+# remove all the candidates divisible by it, and then add it to the primes.
+# Second, there's just a filtering operation on numbers. I think it's
+# probably shorter to write a program that just checks if a number has no
+# numbers mod zero besides 0, 1, and itself. Slower, but shorter is king.
+# Let's try this second strategy first.
+[]
+> 10 # we're probably going to filter a list using this strategy. It's easiest
+# to start working with one element of the list. So let's take some example
+# where we know the answer that we want to get.
+[10]
+> .,2> # let's duplicate it and take a list of values, and drop the first two
+[10 [2 3 4 5 6 7 8 9]]
+> {1$\%!}, # duplicate the ten, and scoot it behind the element, and then run
+# 10 element %, and then ! the answer, so we are left with even multiples
+[10 [2 5]]
+> \; # we want to get rid of the intermediate so it doesn't show up in our
+# solution.
+[[2 5]]
+> 10.,2,-{1$\%!},\; # Okay, let's put our little function together on one line
+[[2 5] [2 5]]
+> ;; # now we just filter the list using this strategy. We need to negate the
+# result with ! so when we get a number with a factor, ! evaluates to 0, and
+# the number is filtered out.
+[]
+> 10,{.,2,-{1$\%!},\;!}, # let's try filtering on the first 10 numbers
+[[0 1 2 3 5 7]]
+> 2> # now we can just drop 0 and 1.
+[[2 3 5 7]]
+> 4.?,{.,2,-{1$\%!},\;!},2> # trick: an easy way to generate large numbers in
+# a few bytes is duplicate and exponentiate. 4.? is 256, and 9.? is 387420489
+[[2 3 5 7] [2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89
+97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193
+197 199 211 223 227 229 233 239 241 251]]
+> ];'4.?,{.,2,-{1$\%!},\;!},2>', # how long is our code for p<256 ?
+[25]
+> ; # this is 25 characters. Can we do better?!
+[]
+> []99,2> # let's go with the first strategy. We'll start with an empty list
+# of primes and a list of candidates
+[[] [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]]
+> (\ # pop left and leave left, we're going to copy this value with the filter
+[[] 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]]
+> {1$%}, # filter out anything that is 0 mod by the popped item one back on the
+# stack
+[[] 2 [3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51
+53 55 57 59 61 63 65 67 69 71 73 75 77 79 81 83 85 87 89 91 93 95 97]]
+> @@+ # great, all the 2-divisible values are off the list! now we need to add
+# it to the running list of primes
+[[3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51 53 55
+57 59 61 63 65 67 69 71 73 75 77 79 81 83 85 87 89 91 93 95 97] [2]]
+> \ # swap back. Now it seems pretty clear when our candidates list is empty
+# we're done. So let's try it with a do loop. Remember we need to duplicate
+# the final value for the pop check. So we add a dot
+[[2] [3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51 53
+55 57 59 61 63 65 67 69 71 73 75 77 79 81 83 85 87 89 91 93 95 97]]
+> {(\{1$%},@@+\.}do;
+[[2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97]]
+> ; # ok that worked. So let's start with our initialization as well.
+[]4.?,2>{(\{1$%},@@+\.}do; # and let's check our work
+[[2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101
+103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199
+211 223 227 229 233 239 241 251]]
+> ,'[]99,2>{(\{1$%},@@+\.}do;', # how long is this?
+[26]
+> ]; # wow this solution is only 26 long, and much more effective. I don't see
+# a way to get any smaller here. I wonder if with unfold we can do better? The
+# strategy here is to use unfold and then at the end grab the first value from
+# each table.
+[]
+> 99,2> # start with the candidates list
+[[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]]
+> (\{1$%}, # pop left and filter
+[2 [3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51 53
+55 57 59 61 63 65 67 69 71 73 75 77 79 81 83 85 87 89 91 93 95 97]]
+> (\{1$%}, # again
+[2 3 [5 7 11 13 17 19 23 25 29 31 35 37 41 43 47 49 53 55 59 61 65 67 71 73 77
+79 83 85 89 91 95 97]]
+89 91 95 97]]
+> {}{(\{1$%},}/ # ok I think it'll work. let's try to put it into an unfold.
+[2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 [[5 7
+11 13 17 19 23 25 29 31 35 37 41 43 47 49 53 55 59 61 65 67 71 73 77 79 83 85
+89 91 95 97] [7 11 13 17 19 23 29 31 37 41 43 47 49 53 59 61 67 71 73 77 79 83
+89 91 97] [11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97] [13
+17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97] [17 19 23 29 31 37 41
+43 47 53 59 61 67 71 73 79 83 89 97] [19 23 29 31 37 41 43 47 53 59 61 67 71 73
+79 83 89 97] [23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97] [29 31 37 41
+43 47 53 59 61 67 71 73 79 83 89 97] [31 37 41 43 47 53 59 61 67 71 73 79 83 89
+97] [37 41 43 47 53 59 61 67 71 73 79 83 89 97] [41 43 47 53 59 61 67 71 73 79
+83 89 97] [43 47 53 59 61 67 71 73 79 83 89 97] [47 53 59 61 67 71 73 79 83 89
+97] [53 59 61 67 71 73 79 83 89 97] [59 61 67 71 73 79 83 89 97] [61 67 71 73
+79 83 89 97] [67 71 73 79 83 89 97] [71 73 79 83 89 97] [73 79 83 89 97] [79 83
+89 97] [83 89 97] [89 97] [97]]]
+> ;] # drop that list of candidates generated at each step and put the items
+# left behind by the unfold at each step (which is the primes) into a list
+[[2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97]]
+> ]; # clear and let's try with larger numbers
+[]
+> 4.?,2>{}{(\{1$%},}/;]
+[[2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101
+103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199
+211 223 227 229 233 239 241 251]]
+>;'4.?,2>{}{(\{1$%},}/;]', # find the length of our solution.
+[21]
+> ]; # only 21 characters for the primes! Let's see if we actually can use this
+# strategy of leaving items behind, now using the do loop to get even shorter!
+> 3.?,2> # candidates
+[[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]]
+> (\{1$%}, # pop and filter
+[2 [3 5 7 9 11 13 15 17 19 21 23 25]]
+> (\{1$%}, # again!
+[2 3 [5 7 11 13 17 19 23 25]]
+> {(\{1$%},.}do;] # try in a do loop and drop the empty list of candidates at
+# the end of the do loop. Don't forget the dot before the closing brace!
+[[2 3 5 7 11 13 17 19 23]]
+> ;4.?,2>{(\{1$%},.}do;] # check our work
+[[2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101
+103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199
+211 223 227 229 233 239 241 251]]
+> ;'4.?,2>{(\{1$%},.}do;]',
+[21]
+>]; # Still 21 characters. there's one other thing to try, which is the prime
+# test known as Wilson's theorem. We can try filtering the items down using
+# this test.
+[]
+> '4.?,2>{.,(;{*}*.*\%},'.~\, # let's run it and take the length
+[[2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101
+103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199
+211 223 227 229 233 239 241 251] 21]
+> ; # Still 21 characters! I think this number is quite good and it's not
+# obvious how to beat it. The problem with GolfScript is there's always someone
+# out there who thinks of some trick you didn't. For instance, you might think
+# you're doing well with a Collatz seq generator of {(}{.2%{3*)}{2/}if}/ until
+# you find that someone figured out {(}{3*).2%6\?/}/ which is so much shorter
+# and cleaner - the unfold operation is nearly half the length!
+########################################################################
+# How to read GolfScript
+########################################################################
+# let's take the gcd from the GolfScript banner. It starts with:
+[]
+> '2706 410'~ # so that's pretty straightforward, that it just evals the list
+# and dumps the results on the stack. It's common to read from stdin which
+# necessitates unpacking with ~
+[2706 410]
+> . # we want to know what that do loop does. the best way to do that is to
+# drop the braces and run the loop one command at a time. We duplicate
+[2706 410 410]
+> @\ # We rearrange
+[410 2706 410]
+> % # we take the modulo
+[410 246]
+> .@\% # repeat. Note we don't need to run the final dot before the closing
+# brace since this is just a value that is popped to check the loop condition
+# you can also replicate the loop end with a semicolon to pop it yourself.
+[246 164]
+> .@\% # again!
+[164 82]
+> .@\% # and finally we hit zero. The loop would exit and ; would pop the zero,
+# leaving you with the gcd of 82.
+[82 0]
+> ;; 2706 410{1$1$%.}do # Clearly this involves knowing about Euclid's method.
+# you can also try a more obvious method like this one here which shows the
+# numbers in sequence.
+[2706 410 246 164 82 0]
+>]; # so sometimes it pays dividends to know the math and you can write short
+# algorithms that rely on easy tricks that aren't immediately obvious.
+[]
+> # let's try looking at the sudoku solver that is on the examples page. I'll
+# skip the unpack step.
+[2 8 4 3 7 5 1 6 9 0 0 9 2 0 0 0 0 7 0 0 1 0 0 4 0 0 2 0 5 0 0 0 0 8 0 0 0 0 8
+0 0 0 9 0 0 0 0 6 0 0 0 0 4 0 9 0 0 1 0 0 5 0 0 8 0 0 0 0 7 6 0 4 4 2 5 6 8 9 7
+3 1]:a 0?:b # again the grid is put into an array. Now, the next step
+# is to define the "@" symbol as the working grid. This is because "@9" is
+# interpreted as two symbols, whereas if you used something like "a" as the
+# variable "a9" is interpreted as a single symbol, and this is not defined,
+# so it will not get run at execution time. You would need a space which is an
+# additional char. On the other hand, redefining built-ins is confusing so I
+# will use "a" and "b" for the "@" and "^" definitions respectively. So the
+# grid is "a" and the zero-index location of the first zero is "b", at index 9.
+[9]
+> ~! # this makes sure that the value is not -1 for find, i.e. -1~ evaluates to
+# 0 so a ! makes it nonzero. ?~! is a great trick for "isn't in the list"
+[0]
+> {@p}* # this prints out the grid the number of times as the previous value,
+# which is how this thing "finishes". So if 0 isn't in the grid, it prints.
+> 10, # let's get the digits 0-9. Zero will be eliminated because our original
+# value is zero so when we look in any row or column, zero is guaranteed to be
+# there.
+[[0 1 2 3 4 5 6 7 8 9]]
+> a 9/ # split the original grid row-wise
+b 9/ # get the row of our checked value, in this case the second row
+= # and we get that row and
+- # take those numbers off the candidates
+[[1 3 4 5 6 8]]
+> a # put the grid on the stack
+b 9% # get the column of the zero
+> # drop the first x values of the grid
+9% # take every ninth digit. We now have the column the zero is in
+> - # pull those items off the candidates list
+[[1 3 5 6]]
+> a 3/ # split the grid into three-long arrays
+b 9% # get the column of the zero
+3/ # is the column in the left (0), middle (1), or right (2) triad?
+ > # pull that many three-groups off
+3% # get every third. Now we have 9 groups - the left side of the grid
+3/ # divide those 9 groups it into thirds
+b 27/ # was the zero on top (0), middle (1), or bottom (2) third of the grid?
+= # since it's the top, grab the top group of triads. You now have the
+ # 1/9th of The sudoku grid where the zero sits
+[[1 3 5 6] [[2 8 4] [0 0 9] [0 0 1]]]
+> {+}*- # flatten those lists and remove those items from the candidates
+# We now have the possible values for the position in question that work given
+# the current state of the grid! if this list is empty then we've hit a
+# contradiction given our previous values.
+[[3 5 6]]
+> 0= # {a b<\+a 1 b+>+}/ # now we've hit this unfold operation. If you run it
+# you'll find we get the grids back. How does that work?! Let's take the first
+# value in the "each" []{}/ operation. This is the best way to figure out what
+# is happening in a mapping situation.
+[3]
+> a # get the grid
+b< # get the grid up to the zero
+\+ # and tack on our value of 3.
+[[2 8 4 3 7 5 1 6 9 3]]
+> a 1b+>+ # and we add on the rest of the grid. Note: we could do 1 char better
+# because 1b+ is equivalent to but, longer than, just b)
+[[2 8 4 3 7 5 1 6 9 3 0 9 2 0 0 0 0 7 0 0 1 0 0 4 0 0 2 0 5 0 0 0 0 8 0 0 0 0 8
+0 0 0 9 0 0 0 0 6 0 0 0 0 4 0 9 0 0 1 0 0 5 0 0 8 0 0 0 0 7 6 0 4 4 2 5 6 8 9 7
+3 1]]
+> 1;; # and the do block runs again no matter what. So it's now clear why this
+# thing exists with an error: if you solve the last digit, then this loop just
+# keeps on rolling! You could add some bytes for some control flow but if it
+# works it works and short is king.
+[]
+
+# Closing Tips for getting to the next level:
+# 0. using lookback might be more effective than swapping around the values.
+# for instance, 1$1$ and \.@.@.\ do the same thing: duplicate last two items
+# but the former is more obvious and shorter.
+# 1. golfscript can be fun to use for messing around with integer sequences or
+# do other cool math. So, don't be afraid to define your own functions to
+# make your life easier, like
+> {$0=}:min; {$-1=}:max; {.,(;{*}*.*\%}:isprime; {.|}:set; # etc.
+# 2. write pseudocode in another language or port a script over to figure out
+# what's going on. Especially useful when you combine this strategy with
+# algebra engines. For instance, you can port the examples-page 1000 digits
+# of pi to python and get:
+# import sympy as sp
+# a, k = sp.var('a'), list(range(20))[1::2]
+# for _ in range(len(k)-1):
+# m = k.pop()
+# l = k.pop()
+# k.append(((l+1)//2*m)//(l+2)+2*a)
+# print(str(k[0]))
+# which gives "2*a + floor(2*a/3 + floor(4*a/5 + 2*floor(6*a/7 + 3*floor(
+# 8*a/9 + 4*floor(10*a/11 + 5*floor(12*a/13 + 6*floor(14*a/15 + 7*floor(16*
+# a/17 + 72/17)/15)/13)/11)/9)/7)/5)/3)"... which makes it much more obvious
+# what's going on than 10.3??:a;20,-2%{2+.2/@*\/a 2*+}* especially when
+# you're new to the language
+# 3. a little math goes a long way. The above prime test uses Wilson's theorem
+# a comparable program testing for factors {:i,(;{i\%!},(;!}:isprime is
+# longer and slower. Also, as discussed above, Collatz is much shorter if
+# you recognize that you can do (3x+1) and then divide by 6 to the power
+# ((3x+1) mod 2). (If x was even, (3x+1) is now odd, so 3x+1 div 6 is x/2.)
+# avoiding conditionals and redundancy can sometimes require such insight.
+# And of course, unless you know this continued fraction of pi it's hard to
+# calculate it in a terse block of code.
+# 4. don't be afraid to define variables and use arrays! particularly if you
+# have 4 or more items to shuffle.
+# 5. don't be afraid to use [some_long_script] to pack a bunch of items in an
+# array after the fact, rather than gathering or adding them later or
+# forcing yourself to use a datastructure that keeps the items in an array
+# 6. sometimes you might get in a jam with - followed by an int that can be
+# solved with ^ to do a symmetric set difference without adding a space
+# 7. "#{require 'net/http';Net::HTTP.get_response(URI.parse(address)).body}"
+# can get any page source from the internet, substituting 'address' for your
+# URL. Try it with an OEIS b-file or wordlists, etc. You can also use the
+# shorter "#{File.open('filename.txt').read}" to read in a file. GolfScript
+# can run "#{any_ruby_code_here}" and add the results to the stack.
+# 8. you can set anything to mean anything, which can be useful for golf:
+# 3:^;^2? => 9 because this set ^ to 3, and 3 2 ? => 9
+# 3:a;a2? => Warning: pop on empty stack - because a2 doesn't exist
+# 3:a;a 2? => 9 - it works again, but takes an extra character over ^2
+# usually you will only want to do this once you're trying to squeeze the
+# last few chars out of your code because it ruins your environment.
+```
+
+* [Run GolfScript online](https://tio.run/#golfscript)
+* [GolfScript's documentation](http://www.golfscript.com/golfscript/builtin.html)
+* [Useful StackExchange thread](https://codegolf.stackexchange.com/questions/5264/tips-for-golfing-in-golfscript)
+* [GolfScript on GitHub](https://github.com/darrenks/golfscript)