www.jammni.de

Logo - Kleiner Drache
Login
Username:

Passwort:

Daten merken
Auto-Login
Registrieren
 
Online
niemand
 
Forumsuche
Suche nach:

Logo - DracheHaskell-Forum

chaot4

Gepostet:
27.07.2009 20:37

Random Funktion mit Rueckgabewert Int  
Guten Tag,

ich programmiere erst seit kurzem Haskell, deswegen, falls Ihr antwortet, setzt bitte nicht so viel voraus, um die Antwort zu verstehen :)
Folgendes Problem habe ich also:
Ich haette gerne eine Funktion mit Rueckgabewert Int, welche eine Zufallszahl ,zwischen zwei per Parametern uebergebenen Werten, erzeugt.
Oder eben, dass eine zufaellige Zahl aus einer uebergebenen Liste herausgesucht wird.

Das hier sollte also dann funktionieren (die Funktion, die ich benoetige nenne ich einfach mal 'zufall')


randmalx :: Int -> Int
randmalx x = x * zufall (parameter)


Eigentlich scheinbar einfach, aber google hat mir absolut nicht weiter geholfen.
Falls Ihr mir helft, bitte postet Codeschnippsel und keinen Link. Ich denke, dass ich Links wohl wieder nicht richtig verstehen werde.

Vielen Dank im Voraus!
Zum Seitenanfang    
 
Siracusa

Gepostet:
28.07.2009 23:25

   
Hallo,

Zufallszahlen in Haskell zu erzeugen ist für Anfänger manchmal etwas verwirrend und nicht so geradlinig wie in anderen Programmiersprachen, daher muss ich mal etwas weiter ausholen.

Zunächst mal ein paar Worte zum Erzeugen von Zufallsszahlen. Will man verschiedene Zufallszahlen durch eine Funktion erzeugen, braucht man eine Möglichkeit sich die letzte Zufallszahl zu merken und daraus beim erneuten Aufruf der Funktion eine neue Zufallszahl zu berechnen, bzw. man merkt sich einen komplexeren Zustand und leitet daraus immer wieder neue Zufallszahlen ab (und ändert den Zustand dann). Ein Objekt, dass sich diesen Zustand merkt und neue Zufallszahlen liefern kann nennt man (Zufalls-)Generator. Wie der Generator intern funktioniert ist jetzt aber nicht weiter wichtig.

Haskell folgt der Idee, dass (pure) Funktionen seiteneffektfrei sein müssen, d.h. das Aufrufen einer Funktion beeinflusst nicht einen internen Zustand und eine Funktion liefert bei gleicher Eingabe immer das gleiche Ergebnis. Beide Bedingungen erfüllt eine Zufallsfunktion nicht, da sie ja bei gleicher Eingabe immer eine andere zufällige Zahl liefern soll und auch den internen Zufallsgenerator immer verändern muss. Was kann man also machen?

Es gibt zwei Möglichkeiten:

Variante 1 (pure Funktionen): Da pure Funktionen seiteneffektfrei sein müssen, muss man den aktuellen Zufallsgenerator "von Hand" an die Funktion übergeben. Man erzeugt sich also mit der Funktion mkStdGen* einen Generator und übergibt ihn mit an die Zufallsfunktion. mkStdGen erwartet außerdem eine Zahl, die den Generator initialisiert. Würde man nun die Zufallsfunktion immer mit dem gleichen Generator aufrufen, würde man jedes Mal die gleiche Zufallszahl erhalten. Bei jedem Aufruf muss also auch ein neuer Generator erzeugt werden (oder der aktuelle verändert werden). Und genau das tut bspw. die Funktion randomR; sie erwartet einen Bereich aus dem eine Zufallszahl erzeugt werden soll in der Form (kleinsteZahl, größteZahl) und einen Generator. Zurückgegeben werden eine Zufallszahl und eine neuer Generator, der wiederum beim erneuten Aufrufen der Zufallsfunktion benötigt wird um eine neue Zufallszahl zu erzeugen. Ein Beispiel:
zufallszahl :: Int
zufallszahl = zahl
where
alterGenerator = mkStdGen 1234
(zahl, neuerGenerator) = randomR (1,10) alterGenerator

Zu beachten ist hier, dass die Funktion immer die gleiche Zufallszahl liefert, da die Variable neuerGenerator nirgends benutzt wird. Würde man eine zweite Zufallszahl erzeugen wollen, müsste man diesen neuen Generator wiederum an randomR übergeben.

Variante 2 (IO-Funktionen): Einfacher ist das Erzeugen von Zufallszahlen mit Hilfe von IO-Funktionen. Dazu solltest du dich aber mit der IO-Monade auskennen, die das Schreiben von Funktionen mit Seiteneffekten erlaubt und eher an imperatives Programmieren erinnert. Du kannst z.B. die Funktion randomRIO benutzen, die wie randomR eine untere und obere Grenze erhält, jedoch keinen Generator benötigt:
zufallszahlIO :: IO Int
zufallszahlIO = do
zahl <- randomRIO (1,10)
return zahl

Diese Methode ist wesentlich einfacher wenn man mehrere Zufallszahlen benötigt. Der Nachteil hierbei ist allerdings, dass man die gesamte Berechnung in einer IO-Monade kapseln muss.

*) alle Funktionen für den Umgang mit Zufallszahlen findest du im Modul System.Random


Ich hoffe das war jetzt alles einigermaßen verständlich und nicht zuviel Information auf einen Schlag. :-)


Viele Grüße,

Siracusa
Zum Seitenanfang    
 
chaot4

Gepostet:
30.07.2009 20:54

   
Vielen, vielen,vielen Dank :)
Ich habe die erste Variante modifiziert und mit dem Wissen aus dem Beitrag, und anderen helfenden Quellen hab ich dann jetzt genau das was ich wollte!
So, falls noch Jemand mal diese Informationen braucht poste ich das zur Vollstaendigkeit!

Mein Generator in Haskell fuer Zufallszahlen sieht folgendermaßen aus:


zufall :: Int -> Int -> [Int]
zufall x y = take y (randomRs (1,100) g)
where
g = mkStdGen x


Zurueckgegeben wird eine Liste mit y Zufaelligen Zahlen zwischen 1 und 100.
Der erste Parameter der Funktion (also x) ist eine zufaellige Zahl, die vom Anweder einmal beim Aufruf des Programms eingegeben werden muss, ab da kann er Zufallszahlen aus der Liste "schoepfen" und kann so ein nicht deterministisches Verhalten haben.

Wen es interessiert warum ich in Haskell so etwas benoetige: Ich will mir einen evolutionaeren Alorithmus programmieren mit Mutation und Crossover (bei denen ich ohne Zufallszahlen nicht weit komme).

Nochmals vielen, vielen Dank an den Herrn/die Dame ueber mir fuer die Hilfe!
Zum Seitenanfang