k4p5

meistens meta
Programming

Einstieg in die Programmiersprache Nim

Anderes als Urgesteine wie C haben jüngere Programmiersprachen wie Go oder Rust bereits Tools an Bord, mit denen sich der geschriebene Quellcode schnell und einfach in ausführbare Programme übersetzen lässt oder mit dem sich Bibliotheken nachladen lassen. Das hilft besonders Anfängern, die damit schnell zu Ergebnissen kommen.

Auch die Nim-Entwickler gehen diesen Weg - und selbst die Installation geht flott von der Hand: So lasst sich Nim unter Unix(64 Bit) über den Befehl:

curl https://nim-lang.org/choosenim/init.sh -sSf | sh

downloaden und installieren. Anschließend ergänzt man noch den Suchpfad etwa in .bashrc oder .zshrc und lädt diese Konfigurationen neu (source ~/.bashrc). Unter Windows oder auf 32-Bit-Systemen muss man für die Installation allerdings andere Wege beschreiten, die aber dokumentiert sind. Anschließend schreibt man folgende Zeilen mit seinem Lieblings-Editor in eine Datei (helloworld.nim):

echo "Hello, World!"

und ruft auf der Konsole den Befehl nim c helloworld.nim auf und erhält im selben Verzeichnis ein ausführbares Programm gleichen Namens. Hallo-Welt-Beispiele sind jedoch etwas schlicht, sodass ich hier gleich ein längeres Beispiel folgen lasse. Es ist ein kleines Konsolenprogramm, dass Textzeilen aus einer Datei einliest, per Zufall ein von diesen Zeilen auswählt und ausgibt. Die Zeilen besitzen einen per Doppelpunkt abgetrennten Prefix (de, en), sodass man zudem auch mehrsprachige Text ausgeben kann.

import parseopt
import os
import strutils
import random
import system

Bibliotheken und eigene Module lädt Nim ähnlich Python über import. Nim bringt bereits eine Reihe von Standard-Modulen mit, weitere Bibliotheken lädt man bequem mit dem Modulemanager nimble nach.

var lang: string = "en"

Variablen deklariert man jedoch etwas anders: Nach dem Schlüsselwort var folgt der Name sowie der Variablentyp. Weist man anschließend mittels = der Variable einen Wert zu, kann man den Variablentyp auch offenlassen, da Nim ihn aus dem Variablenwert ermittelt.

Zeilen die mit einer Raute beginnen interpretiert Nim als Kommentar, ganze Textblöcke lassen sich in Nim mit den beiden Zeichenfolgen #[ und ]# auskommentieren.

#[
a little help procedure, 
which shows usage and options
]#

Funktionen oder Prozeduren definiert man in Nim über das Schlüsselwort proc.

proc hilfe() =
 echo "Usage: "
 echo " Parameters: "
 echo " -l | --lang .... set the language eg -l:de sets german"
 echo " -h | --help .... show this help"
 quit(1)

Wichtige Dinge wie etwa eine Bibliothek um Kommandozeilen-Argumente auszuwerten hat Nim (ähnlich wie Python) bereits an Bord. Die folgenden Zeilen illustrieren deren Einsatz:

import parseopt
[...]
when declared(commandLineParams):
 var p = initOptParser()
 while true:
  p.next()
  case p.kind
  of cmdEnd: break
  of cmdShortOption, cmdLongOption:
    if p.val == "":
      if p.key == "h" or p.key == "help":             
        hilfe() 
    else:
      if p.key == "l":
        lang = p.val
  of cmdArgument:
    echo "Argument: ", p.key

Nach dem Import der Standard-Bibliothek parseort lässt sich mit der Funktion declared prüfen, ob überhaupt Kommandozeilen-Parameter übergeben wurden: Ist das der Fall, wird der Parser eingerichtete und die Parameter nacheinander ausgewertet. Anders als Python kann Nim mittels case zwischen mehreren Fällen unterscheiden, was in diesem Falle sehr günstig und übersichtlich ist.

Alle bisher gezeigten Code-Beispiele befassen sich hingegen nicht direkt mit der obengenannten Hauptfunktion des Programms. Die folgenden 15 Zeilen sind dafür zuständig.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
let contents = readFile("zitate.de.txt")
var lines = contents.splitLines()

randomize()
shuffle(lines)

var count: int = 0

for line in lines:
 if count < 1:
  if startsWith(line, lang & ":"):
   var ausgabe = line
   ausgabe.removePrefix(lang & ":")
   echo ausgabe
   count = count + 1

Während Zeile 1 die Datei "zitate.de.txt" einliest, zerlegt der folgende Befehl den Text in einzelne Zeilen und speichert das Ergebnis im Array lines.

Die beiden Befehle in den Zeilen 4 und 5 entstammen der Bibliothek random: Während randomize() den Zufallsgenerator initialisiert, würfelt shuffle(lines) die Elemente des Array durcheinander.

Die nachfolgende For-Schleife soll nun das erste Element im Array lines ausgeben, dessen Prefix dem Wert von lang - also der eingestellen Sprache entspricht. Dazu überprüft es den String line mittels startsWith (stammt aus strutils), gibt ihn ggf. aus und setzt count auf 1 - was im nächsten Durchlauf die Schleife abbricht.

Diese und andere Beispiele findet Ihr in diesem Github-Repositorium.