Skip to content

The Special Little Symbol

Yesterday I showed you a FizzBuzz solution in YS. Here it is again:

!YS-v0

defn main(n=100):
  each x (1 .. n): !:say
    or? _ x:
      str ((x % 3).! &&& 'Fizz'):
          ((x % 5).! &&& 'Buzz')

See that _ sitting there in the middle all by itself?

What's that all about?

Well _ is a special symbol in YS, and it means different things in different contexts.

The _ Placeholder🔗

In that code we want the result of the str(...) call, which will either be Fizz, Buzz, FizzBuzz or an empty string. If it was an empty string then we want to use the value of x.

Basically we wanted or?(str(...) x) or put another way str(...) ||| x.

In this case the str(...) call was to big to fit on one line. So we used _ to mean: put the big expression after the : where the _ is.

This ends up being a really helpful when the first argument is a function and you want to use a non-trivial anonymous function for it. A common case for this is the reduce function.

Here's a reduce to find prime numbers:

!YS-v0

say:
  reduce _ [2] (3 .. 100):
    fn(primes number):
      if primes.map(mod + number).some(zero?):
        primes
        conj(primes number)

Let's run it:

$ ys primes.ys
[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]

The reduce function takes 3 arguments:

  • A function to call for each element in the list
  • An initial value
  • A list to reduce

It would be nicer the the function came last because the 2nd and 3rd arguments are usually short.

If we had already defined the prime-finder function we could have written:
reduce prime-finder [2] (3 .. 100).

But often the function is not reusable so we just want to write it inline.

The _ placeholder lets us get the best of both worlds.

The _ Dummy Variable🔗

In multi-variable assignments we can do this:

_ a b _ c =: a-list

Which could be written as:

a b c =: + [a-list.1, a-list.2, a-list.4]

Use _ as a dummy variable to ignore some of the values.

You could also use it in function arguments:

$ ys -e '
defn shift([_ *rest]): rest
say: (0 .. 4):shift'
(1 2 3 4)

Here we define a shift function that uses _ to ignore the first argument and return the rest.

The _ Position Indicator🔗

Most common functions used in chains, are "smart" about their arguments.

For example, these are all equivalent:

list.take(5)
5.take(list)
take(5 list)

The take function takes a number and a list. The . chain operator puts the LHS into the first position.

That means that list.take(5) should have been evaluated as take(list 5) which is wrong and would throw an error.

But YS handles take and other common functions specially and checks the argument types at runtime and does the right thing for you.

Unforunately, this is not true for all functions, and also the runtime check takes some time.

You can also write that as: list.take(5 _). The _ indicates the position to put the LHS into. It also disables the "smart" runtime check since you told it explicitly where things should go. This makes it a little faster to run, which might be important sometimes.

If you wrote your own foo-bar function that also took a number and a list, you'd need to use _ for list.foo-bar(5 _) because foo-bar wouldn't have the special "smart" property.

Using _ in Anonymous Functions🔗

We've already seen this but _ is the shorthand for the first argument in an anonymous function.

$ ys -e '
squared =: \(_ * _)
say: 8:squared
'
64

The Previous Document Value🔗

In a multi-document YAML file, the _ symbol is the previous document value.

$ ys -e '!YS-v0
--- !data
foo: blue
bar: 10
--- !code
say: _.foo * _.bar
'
blueblueblueblueblueblueblueblueblueblue

You can use this for one liners that take a file and also a -e expression argument:

$ curl -sL https://gist.github.com/gsscoder/e0e905fbef23376aabfa695d85d8ef5c/raw |
ys -e 'say: rand-nth(_)' -
Finnegan

https://gist.github.com/gsscoder/e0e905fbef23376aabfa695d85d8ef5c External link is a JSON (aka YAML) file with a sequence of first names; posted as a GitHub Gist.

Since YS always evaluates the -e expression after the file (- for stdin here) is evaluated, _ is the value of the evaluated file.


I hope I remembered all of the places you can use _ in YS.

It's quite possible that YS will have more places to use _ in the future.

If you have ideas for more places to use _ in YS, please let me know in the comments.

Comments