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-v0
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!