About this ‘A Language a Day’ Advent Calendar
This article became a part of my book ‘A Language a Day’, which you can get in both electronic and paper format. Languages covered in the book: C++, Clojure, Crystal, D, Dart, Elixir, Factor, Go, Hack, Hy, Io, Julia, Kotlin, Lua, Mercury, Nim, OCaml, Raku, Rust, Scala, and TypeScript.
Welcome to Day 18 of this year’s A Language a Day Advent Calendar. Today’s topic is introduction to the Hy programming language.
Facts about the language
- A dialect of List
- Basically, it is Python written with the syntax of Lisp
- Appeared in 2013
- Website: hylang.org
Installing and running Hy
To install Hy, you need to have Python installed first. Then, you simply install a package using pip
:
$ pip install git+https://github.com/hylang/hy.git
To run a program, use the hy
command-line tool:
$ hy hello-world.hy
Hy is an interesting language that can help in introducing you to the world of Lisp-like languages. If you are familiar with Python, you can concentrate on re-thinking Python programs as if they would be written in Lisp with all that ‘inverted’ syntax and lots of parentheses.
Hello, World!
Here is a simple Hello, World! program in Hy:
(print "Hello, World!")
Looking at the Python code
The --spy
command-line option allows you to see how your program is being transformed:
$ hy --spy < hello-world.hy
In the output, you can see the equivalent Python code:
=> print('Hello, World!')
Variables
To create (or to bind) a variable, use the setv
built-in feature.
(setv username "John") (print (+ "Hello, " username "!"))
In this example, you can also see how to concatenate strings, and on a broader scale, how to use operators: instead of a + b
, you type (+ a b)
.
Functions
Functions are created with the defn
keyword. It is followed by the function name and the function arguments in square brackets:
(defn greet [username] (print (+ "Hello, " username "!"))) (greet "John")
Calling a function is done in a separate pair of parentheses, similarly to how we already invoked print
.
Calling a method
There are two ways of calling a method on an object. For example, in the following code, the Python’s str.upper()
method is called on a variable. You can use either syntax:
(setv greeting "hello") (print (greeting.upper)) (print (.upper greeting))
A Factorial example
I hope that at this moment, you can write a factorial function yourself. Here is my solution:
(defn factorial [n] (if (< n 2) 1 (* n (factorial (- n 1))))) (print (factorial 1)) ; 1 (print (factorial 5)) ; 120 (print (factorial 7)) ; 5040
Take in mind that you do not need a return
statement to return a value from the function. The expressions such as n < 2
or n - 1
are spelled as (< n 2)
and (- n 1)
in Hy.
Classes
Let us see how you define classes in Hy with the defclass
keyword. Here is a class for keeping the name and the age of a person:
(defclass Person [object] (defn --init-- [self name age] (setv self.name name) (setv self.age age)) (defn info [self] (+ self.name " is " (str self.age) " y.o."))) (setv john (Person "John" 30)) (print (.info john)) ; John is 30 y.o. (setv alla (Person "Alla" 20)) (print (.info alla)) ; Alla is 20 y.o.
Notice how Hy transforms hyphens in identifier names to underscores. In a similar manner, you could, for example, name a method info-string
and it will be trans-compiled to info_string
.
A Polymorphic example
Hierarchy is Python is expressed as an argument to the class name, so in Hy, the base class is mentioned in square brackets. The full polymorphic example code is shown below.
(defclass Animal [object] (defn what [self] "it is an animal")) (defclass Dog [Animal] (defn info [self] (+ "This is a dog and " (.what self)))) (defclass Cat [Animal] (defn info [self] (+ "This is a cat and " (.what self)))) (setv zoo [(Cat) (Dog) (Cat) (Dog)]) (for [x zoo] (print (.info x)))
In this program, both Dog.info
and Cat.info
call a method of their base class: Animal.what
. The program prints the following output:
This is a cat and it is an animal This is a dog and it is an animal This is a cat and it is an animal This is a dog and it is an animal
Using modules
To implement the next program we need to import a module, so let us see how you do it with Hy:
(import datetime) (print (.now datetime.datetime))
Sleep sort
For the reference, here is a Python program that implements the Sleep sort algorithm. For simplicity, a number of intermediate variables are introduced. In real code, this may not be needed, but it is very handy for converting to Hy.
import time import threading data = [10, 4, 2, 6, 2, 7, 1, 3] for n in data: delay = n / 10 timer = threading.Timer(delay, print, [n]) timer.start() time.sleep(2)
And here is the corresponding program in Hy:
(import time) (import threading) (setv data [10, 4, 2, 6, 2, 7, 1, 3]) (for [n data] (setv delay (/ n 10)) (setv timer (threading.Timer delay print [n])) (.start timer)) (.sleep time 2)
Resourses
There are not that many resources outside of the Hy website and the corresponding GitHub repository. Nevertheless, this language is a great thing to try before learning any other Lisp-like language.
You can find source codes of the examples shown in this article in my repository on GitHub.
Next: Day 19. Red
One thought on “Hy at a Glance — A Language a Day, Advent Calendar Day 18/24”