Getting Started With Nim
Having been a long time Python user I often find myself reaching for it over languages. When I saw the announcement for version 0.10.2 of Nim on Hacker News it got me interested in learning another language, especially one that compiles to C and executables. I have some experience with C and C++ having done some Arduino projects, but my biggest memory of it is from a programming data structures class I took as an undergrad. All that memory management somehow didn't fit my brain's way of thinking and it turned me off to programming as a profession.
Of course that didn't stop me from learning to program, it just drove me to interpreted languages like PHP and Python. I remember googling "garbage collection" when I learned about Python and saying "This looks like the language for me." What followed was 14+ years of enjoyable programming. Now my skills have improved to the point that I'm looking to broaden my language talents and Nim looks like a good one to add.
Some of the things that attracted me to Nim:
- The Python like syntax
- Static typing with basic type inference
- Garbage collector
- Compiles to C and then to an executable
I'm hoping that the syntax and garbage collection will allow me to quickly getting programs more useful than "Hello World" running. The static typing and compiling should make things less error prone and fast, and the executable means working programs should be more portable than Python.
My first Python project involved creating a linear regression using least squares to fit a calibration line to data collected off a sensor array. Since SciPy and NumPy weren't around/mature at the time I cracked open my statistics textbook and wrote all the functions needed to fit the data. Since Nim doesn't appear to have a statistics module and given my statistics knowledge is a little rusty I thought starting a basic nim-statistics
module would both give me a good understanding of Nim basics and refresh my stats.
I won't go over installing Nim or leaning the basics since that is covered in other places. A lot of what I will show here will be based on other people's code and reading the standard library. So let's start with something simple, a Gaussian Distribution. First we'll import the built-in math
module since we know we'll be needing procedures from it. Then we'll define an object to hold the distribution's parameters.
import math type GaussDist* = object mu, sigma: float
Some things to note:
- The
GaussDist
type inherits from the baseobject
type and has two parameters with typefloat
- Symbols that are marked with
*
are exported by the module (where another modules uses theimport
function). Soimport math
imports everything mark with an asterisk in the math module and this module will export theGaussDist
type.
Now let's add some functionality.
import math type GaussDist* = object mu, sigma: float proc NormDist*(): GaussDist = ## A Normal Distribution is a special form of the Gaussian Distribution with ## mean 0.0 and standard deviation 1.0 result.mu = 0.0 result.sigma = 1.0 proc mean*(g: GaussDist): float = result = g.mu proc standardDeviation*(g: GaussDist): float = result = g.sigma proc variance*(g: GaussDist): float = result = math.pow(g.sigma, 2) when isMainModule: var n = NormDist() var gnorm = GaussDist(mu: 0.0, sigma: 1.0) assert(n.mean == gnorm.mean) assert(n.standardDeviation == gnorm.standardDeviation) assert(n.variance == gnorm.variance) echo "SUCCESS: Tests passed!"
More notes:
- The
mean
,standardDeviation
, andvariance
procedures are all available from themath
module but don't know how to handle theGaussDist
type so we use Nim's ability to overload procedures to implement that here. - In the
NormDist
procedure you can see an example of the use of Nim's default retun valueresult
. Since result is aGaussDist
type due to the procedure's definition we can just assign the parameter values without needing to create an intermediate variable. -
math.pow
could be replaced withpow
since the later is included in the import, but doing it this way makes it clear where the procedure is coming from. - The
when isMainModule
check gives us a convenient place to put tests since what's in the block won't be executed when the module is imported.
Finally, let's add the distribution functions.
import math ## Some additional functions from math.h are needed ## that aren't included in the math module proc erf(x: float): float {.importc: "erf", header: "<math.h>".} ## computes the error function (also called the Gauss error function) type GaussDist* = object mu, sigma: float proc NormDist*(): GaussDist = ## A Normal Distribution is a special form of the Gaussian Distribution with ## mean 0.0 and standard deviation 1.0 result.mu = 0.0 result.sigma = 1.0 proc mean*(g: GaussDist): float = result = g.mu proc standardDeviation*(g: GaussDist): float = result = g.sigma proc variance*(g: GaussDist): float = result = math.pow(g.sigma, 2) ## The distribution functions are from ## http://en.wikipedia.org/wiki/Normal_distribution proc pdf*(g: GaussDist, x: float): float = var numer, denom: float numer = math.exp(-(math.pow((x - g.mu), 2)/(2 * math.pow(g.sigma, 2)))) denom = g.sigma * math.sqrt(2 * math.PI) result = numer / denom proc cdf*(g: GaussDist, x: float): float = var z: float z = (x - g.mu) / (g.sigma * math.sqrt(2)) result = 0.5 * (1 + erf(z)) when isMainModule: var n = NormDist() var gnorm = GaussDist(mu: 0.0, sigma: 1.0) assert(n.mean == gnorm.mean) assert(n.standardDeviation == gnorm.standardDeviation) assert(n.variance == gnorm.variance) assert(n.pdf(0.5) == 0.3520653267642995) assert(n.cdf(0.5) == 0.6914624612740131) echo "SUCCESS: Tests passed!"
Alright, so that's a good start. Some final notes:
- The Nim
math
module doesn't include theerf
procedure but it's available in the standard C library so it's and easy import here. - There are multiple ways to call Nim procedures and in this post's example I've chosen to use the method call syntax (
obj.method()
) because it looks more natural to me.
This was a nice first go at learning Nim and although it didn't really exercise some of the 'wow' features it gave me a good introduction to the language and a starting point to grow from. Hopefully I'll be able to flesh out the statistics module and as I learn more about Nim I will post it here.
Reference
Nim Manual
Tutorial 1
Tutorial 2
Garbage Collector
Nim Standard Library