YS Symbols
Today I'd like to show you why I love how YS handles symbols.
Symbols are used to represent variables, functions, and other names in the language.
All the shorties I showed you yesterday were symbols. Symbols that resolved to functions.
Clojure / Lisp Symbols🔗
In languages like Python, symbols are generally strings composed of alphanumeric
characters and _.
They generally can't start with a number.
In Clojure, like most Lisps, the rules accept many more characters. They still can't start with a number.
From the Clojure Language Reference
:
Symbols begin with a non-numeric character and can contain alphanumeric characters and *, +, !, -, _, ', ?, <, > and = (other characters may be allowed eventually).
That's a lot of possibilities!!
Should +<*@?=! be a symbol?
Apparantly!
YS Symbols🔗
If you look through the Clojure core library source code
,
you'll see that that almost every symbol is made of alphanumeric characters and
the
- character.
A few end with !, ?, * and a few use + instead of - to separate words.
There's a handful of other weirdos, but for the most part, it's a very sane
subset of what is actually allowed.
YS chose to only allow the sane subset; even stricter that what I just described.
YS symbols are alphanumeric words separated by a single - character and start
with an alphabetic character.
They may end with ?, ! or +.
Even with this very simple rule, YS can still access all the things it needs from Clojure.
Any Symbol, Any Time🔗
One of the aspects of both YS and Clojure that I love is that you can use any word you want to as a variable name. YS and Clojure have no concept of "keywords" or "reserved words".
Imagine using if as a variable name in Python:
$ python -c 'if = 42'
File "<string>", line 1
if = 42
^
SyntaxError: invalid syntax
No way!
You need to make up a new name for your variable.
Something like if_ is common when it's important to use the name if.
In YS, you can use if as a variable name.
$ ys -e 'if =: 42' -e 'say: if'
42
You just can't use the if function after that within the same scope.
$ ys -e 'if =: 42' -e 'if if: say(if)'
42
Wait, what?
It actually worked!
I honestly did not expect that to work.
I've figured it out but I can't explain why right now.
Let's just say that if is special
.
Let's try something else.
$ ys -e 'r =: range(65 70).map(C)' -e 'say: zipmap(r range())'
{A 0, B 1, C 2, D 3, E 4}
Neato, but r is bad name.
Let's change it to range!
$ ys -e 'range =: range(65 70).map(C)' -e 'say: zipmap(range range())'
Error: Attempting to call unbound fn: #'main/range
Yep, that's what I expected.
We changed range for a function to a list of characters, so we can't just use
it as a function again.
Symbols inside functions🔗
Functions provide a better scope to use whatever you want as a variable name.
Imagine we've written a dice-roll function and we want t call it and save the
dice roll.
What should we call the variable?
Well most of the time, I'd want to call it what it is: dice-roll!
!ys-0
defn main():
dice-roll =: dice-roll()
say:
if dice-roll.0 == dice-roll.1:
then: "Dice numbers match: $dice-roll"
else: "Dice numbers are different: $dice-roll"
defn dice-roll(): +
[rand-int(6).++ rand-int(6).++]
Running this, we get:
$ ys dice.ys
Dice numbers match: [6 6]
$ ys dice.ys
Dice numbers are different: [6 4]
When you need to make up a name for something in YS, just use whatever makes sense!