I am a big advocate of learning multiple programming languages. That's mostly because I tend to get bored with the languages I use the most. It also teaches me new and interesting ways to approach programming.
Writing the same program in multiple languages is a good way to learn their differences and similarities. Previously, I wrote articles showing the same sample data plotting program written in C & C++, JavaScript with Node.js, and Python and Octave.
This article is part of another series about writing a "guess the number" game in different programming languages. In this game, the computer picks a number between one and 100 and asks you to guess it. The program loops until you make a correct guess.
Learning a new language
Venturing into a new language always feels awkward—I feel like I am losing time since it would be much quicker to use the tools I know and use all the time. Luckily, at the start, I am also very enthusiastic about learning something new, and this helps me overcome the initial pain. And once I learn a new perspective or a solution that I would never have thought of, things become interesting! Learning new languages also helps me backport new techniques to my old and tested tools.
When I start learning a new language, I usually look for a tutorial that introduces me to its syntax. Once I have a feeling for the syntax, I start working on a program I am familiar with and look for examples that will adapt to my needs.
What is Racket?
Racket is a programming language in the Scheme family, which is a dialect of Lisp. Lisp is also a family of languages, which can make it hard to decide which "dialect" to start with when you want to learn Lisp. All of the implementations have various degrees of compatibility, and this plethora of options might turn away newbies. I think that is a pity because these languages are really fun and stimulating!
Starting with Racket makes sense because it is very mature and versatile, and the community is very active. Since Racket is a Lisp-like language, a major characteristic is that it uses the prefix notation and a lot of parentheses. Functions and operators are applied to a list of operands by prefixing them:
(function-name operand operand ...)
(+ 2 3)
↳ Returns 5
(list 1 2 3 5)
↳ Returns a list containing 1, 2, 3, and 5
(define x 1)
↳ Defines a variable called x with value of 1
(define (f x y) (* x x))
↳ Defines a function called f with two parameters called x and y that returns their product.
This is basically all there is to know about Racket syntax; the rest is learning the functions from the documentation, which is very thorough. There are other aspects of the syntax, like keyword arguments and quoting, but you do not need them for this example.
Mastering Racket might be difficult, and its syntax might look weird (especially if you are used to languages like Python), but I find it very fun to use. A big bonus is Racket's programming environment, DrRacket, which is very supportive, especially when you are getting started with the language.
The major Linux distributions offer packaged versions of Racket, so installation should be easy.
Guess the number game in Racket
Here is a version of the "guess the number" program written in Racket:
#lang racket
(define (inquire-user number)
(display "Insert a number: ")
(define guess (string->number (read-line)))
(cond [(> number guess) (displayln "Too low") (inquire-user number)]
[(< number guess) (displayln "Too high") (inquire-user number)]
[else (displayln "Correct!")]))
(displayln "Guess a number between 1 and 100")
(inquire-user (random 1 101))
Save this listing to a file called guess.rkt
and run it:
$ racket guess.rkt
Here is some example output:
Guess a number between 1 and 100
Insert a number: 90
Too high
Insert a number: 50
Too high
Insert a number: 20
Too high
Insert a number: 10
Too low
Insert a number: 12
Too low
Insert a number: 13
Too low
Insert a number: 14
Too low
Insert a number: 15
Correct!
Understanding the program
I'll go through the program line by line. The first line declares the language the listing is written into: #lang racket
. This might seem strange, but Racket is very good at writing interpreters for new domain-specific languages. Do not panic, though! You can use Racket as it is because it is very rich in tools.
Now for the next line. (define ...)
is used to declare new variables or functions. Here, it defines a new function called inquire-user
that accepts the parameter number
. The number
parameter is the random number that the user will have to guess. The rest of the code inside the parentheses of the define
procedure is the body of the inquire-user
function. Notice that the function name contains a dash; this is Racket's idiomatic style for writing a long variable name.
This function recursively calls itself to repeat the question until the user guesses the right number. Note that I am not using loops; I feel that Racket programmers do not like loops and only use recursive functions. This approach is idiomatic to Racket, but if you prefer, loops are an option.
The first step of the inquire-user
function asks the user to insert a number by writing that string to the console. Then it defines a variable called guess
that contains whatever the user entered. The read-line
function returns the user input as a string. The string is then converted to a number with the string->number
function. After the variable definition, the cond
function accepts a series of conditions. If a condition is satisfied, it executes the code inside that condition. These conditions, (> number guess)
and (< number guess)
, are followed by two functions: a displayln
that gives clues to the user and a inquire-user
call. The function calls itself again when the user does not guess the right number. The else
clause executes when the two conditions are not met, i.e., the user enters the correct number. The program's guts are this inquire-user
function.
However, the function still needs to be called! First, the program asks the user to guess a number between 1 and 100, and then it calls the inquire-user
function with a random number. The random number is generated with the random
function. You need to inform the function that you want to generate a number between 1 and 100, but the random
function generates integer numbers up to max-1
, so I used 101.
Try Racket
Learning new languages is fun! I am a big advocate of programming languages polyglotism because it brings new, interesting approaches and insights to programming. Racket is a great opportunity to start learning how to program with a Lisp-like language. I suggest you give it a try.
Comments are closed.