Was ich möchte
Auf meinem Weg, Haskell zu lernen, habe ich heute etwas über Commandzeilen Argumente gelernt.
Dabei half mir LM Studio und das kleine LLM Ministral-3-3b.
Ich bat Ministral mir eine Programm zu schreiben, um mir anzusehen wie man in Haskell mit Commandzeilen Argumenten bei Programmaufruf umgeht.
Hier mein Prompt:
Bitte schreibe mir ein Haskell Programm das beim Aufruf
4 Zahlen als Kommandozeilen Agrumente erwartet
und diese addiert und zurückgibt.
Ministral bot mir folgende Lösung an:
module Main where
import System.Environment (getArgs)
main :: IO ()
main = do
args <- getArgs
if length args >= 4
then do
let numbers = map read [args !! 0 .. args !! 3]
sumResult = sum numbers
putStrLn $ "Die Summe der Zahlen ist: " ++ show sumResult
else
putStrLn "Bitte gib genau vier Zahlen als Kommandozeilenargumente an."
Natürlich mit noch ein wenig mehr ausschmückendem Text und blabla.
Vibe-Bugging
Allerdings : ghc sagt nein. Was, warum und wieso?
Lets dive into.

Beim Kompilieren mit ghc sumFour.hs -o sumFour kommt es zur Fehlermeldung.
Deep-Dive
Zu nächste möchten wir die Funktion getArgs benutzen. Alles fein.
Importier System.Environment (getArgs),
benutze es in args <- getArgs.
Fort an sind die Commandline Argumente in der Liste args zu finden. Das wollte ich wissen.
Haskell beschwert sich, dass in let numbers = map read [args !! 0 .. args !! 3] etwas nicht stimmt.
Was soll uns diese Zeile sagen?
Der Ausdruck args !! n soll aus der List args das n-te Element wiedergeben. Dabei ist !! ein index-Operator. (Real World Haskell S. 196).
Der Enumeration-operator .. erwartet etwas woraus er eine Sequenz machen kann. (Real World Haskell S. 10).
Zum Beispiel :
ghci> [1 .. 10]
[1,2,3,4,5,6,7,8,9,10]
Aha. Ministarl möchte eine Liste von Argument-0 bis Argument-3 bilden. Dann soll map auf dieser Liste die Funktion read anwenden. read soll wiederum aus jedem Argument (vom Typ String) eine Zahl machen.
Soweit so klar.
Heurika
ABER HIER KNALLT ES. WEILargs !! n liefert einen String/Char-Array aus args.
Also ist :[args !! 0 .. args !! 3] gleichbedeutend mit: [string .. string].
Haskell kann hier nicht interpretieren, was es machen soll. Der Enumeration-Operator erkennt keine Ober und Untergrenze.
Ministarl möchte eine Liste von Argument-0 bis Argument-3 bilden. Aber das funktioniert so nicht.
Wie sieht die Primitive Lösung aus?
Man zähle alle 4 Argumente einzeln auf.
let numbers = map read (args!!0, args!!1, args!!2, args!!3)
Ha Ha – das funktioniert.
Das geht noch besser …
Aber welcher Programmiere will so etwas schon hard-coden und vor allem das heilige DRY-Prinzip verletzen und immer wieder „das selbe“ schreiben.
Alsoooooo … das muss doch eleganter gehen. Und kürzer. und ich will mich schlau fühlen indem ich eine andere Lösung finde (ob die besser ist, wissen wir noch nicht =) )
Überlegung: wir haben mit args bereits eine Auszählung/Liste.
Also sollte doch let numbers = map read args laufen?
Surprise – ja tut es.
$: ghc sumFour.hs -o sumFour
Loaded package environment from /home/.../default
[1 of 2] Compiling Main ( sumFour3.hs, sumFour3.o )
[2 of 2] Linking sumFour [Objects changed]
$: ./sumFour 1 1 1 1 1 1
Die Summe der Zahlen ist: 6
$:
Yeay – hmmmm.
Es funktioniert. Aber es verarbeitet mehr als 4 Argumente. Die Anforderung lautet, es sollen 4 und nicht mehr oder weniger sein (ja die vier ist willkürlich, trotzdem).
Lets change a running system. (Hat ja noch nie nicht funktioniert.)
Es läuft (wieder)
Wie sieht es aus, wenn wir let numbers = map read (take 4 args) benutzen?
Yup. Das funktioniert. Endlich.
Zugegeben: ich musste erst etwas probieren. aber das kriege ich hier nicht mehr rekonstruiert um es auf zu schreiben.
Damit ist der lauffähige Code um 4 Zahlen, als Argumente übergeben, zu summieren:
module Main where
import System.Environment (getArgs)
main :: IO ()
main = do
args <- getArgs
if length args >= 4
then do
let numbers = map read (take 4 args)
sumResult = sum numbers
putStrLn $ "Die Summe der Zahlen ist: " ++ show sumResult
else
putStrLn "Bitte gib genau vier Zahlen als Kommandozeilenargumente an."
Korrektur
Nach Rückfrage korrigiert sich Ministarl selber. Wunderbar. Nochwas gelernt.


Erfreulicherweise sind die Problemlösung von Ministral und von mir nach 1-2 Stunden Debugging, Probieren und Lernen die selben.
Was geht (sonst noch)
Pedantisch könnte man jetzt noch folgende Eigenschaften implementieren:
- Fehlermeldungen wenn die Anzahl der Argumente von 4 abweicht
Das Programm muss sich darauf verlassen können das genau n Argumente angeboten werden, wenn genau n Argumente angefordert werden.
Ich habe gelernt, Fehler wie diesen, zu viel oder zu wenig, auch explizit zu machen.
Es geht darum nicht einfach heimlich zu verschweigen wenn zu viel an kommen.
Klar könnte man ignorieren. NEIN macht man nicht.
Aber das kann an anderer Stelle und vor allem bei ÄNDERUNGEN zu Problemen führen.
Merke: keine Fehler heimlich verschweigen oder still und leise ignorieren UND es wird sich garantiert etwas ändern. - Der Klassiker: nur numerische eingaben akzeptieren. Falls ein Argument nicht Numerisch ist => explizite Fehlermeldung als Hilfe wo die Grütze passiert ist.
Was habe ich gelernt
- Commandline Argumente werden mit
System.Environment getArgsundargs <-getArgsverarbeitet - die Umwandlung von String nach Int kann mit
readerledigt werden - mit
mapwendet man eine Funktion auf eine Liste an liste !! nist der Index-Operator und liefert das n-te Element der Listelb .. ubbildet Seqeunzen von lower-bound bis upper-bound.- Ministral kann Haskell, braucht aber Aufsicht und Kontrolle.
- auch das korrigieren kann das kleine LLM erledigen.