2013-04-25 3 views
5

Ich erstellen eine Haskell-Anwendung, die eine Zufallszahl in einer Endlosschleife generiert (nur wenn von einem Client angefordert). Allerdings sollte ich für diesen Zweck nur reine Funktionen verwenden. Ist es sicher, randomIO mit unsafeperformIO ohne drastische Stabilität oder Leistungsrisiko zu wickeln?Risiken der Verwendung von unsafeperformIO auf randomIO

+5

Sie sollten ['random'] (http://hackage.haskell.org/packages/archive/random/latest/doc/html/System-Random.html#v:random) oder [' randomR'] verwenden (http://hackage.haskell.org/packages/archive/random/latest/doc/html/System-Random.html#v:randomR) in reinem Code. –

+1

NEIN! Du könntest 'unsafeInterleaveIO' rechtfertigen, aber nichts Zufall ist rein! –

+6

@PhilipJF: "Nichts Zufälliges ist rein"? Ich würde sagen Dinge wie (Not-in-Place) Quicksort mit zufälliger Pivot sind reine Algorithmen in Ordnung: Die Zufälligkeit kann von außen nicht beobachtet werden, außer durch Performance-Variationen, die sowieso nur irgendeine Bedeutung in der 'IO'-Monade haben. – leftaroundabout

Antwort

12

Jede Verwendung von unsafePerformIO sollte durch einen Nachweis gerechtfertigt werden, dass der resultierende Wert immer noch rein ist. Die Strenge des Beweises liegt bei Ihnen und der Wichtigkeit der Arbeit. Zum Beispiel sollte dieser erbärmliche Gebrauch unsafePerformIO und randomIO sicher sein, weil Sie beweisen können, dass, wenn slowTrue irgendetwas zurückgibt, es True zurückgibt.

import System.Random 
import System.IO.Unsafe 
import Data.Int 

slowTrue = unsafePerformIO $ go 
    where 
    go = do 
     x1 <- randomIO 
     x2 <- randomIO 
     if ((x1 :: Int16) == x2) then return True else go 

Die folgende verlockend Definition eines globalen, ist möglicherweise Zufallsvariablen nicht sicher:

rand :: Bool -> Int 
rand True = unsafePerformIO randomIO 
rand False = 0 

Das Problem ist, dass der gleiche Ausdruck nun unterschiedliche Werte ergeben wird:

main = do 
    print (rand True) 
    print (rand True) 

Drucke hier:

-7203223557365007318 
-7726744474749938542 

(zumindest wenn kompiliert ohne Optimierungen - aber das betont nur die Fragilität der unsachgemäßen Verwendung von unsafePerformIO).

+0

Das ist eine interessante Frage. Die Definition auf oberster Ebene 'unknown = unsafePerformIO randomIO' ist eigentlich sicher, wenn der Compiler den Körper von' unknown' nur einmal auswerten wird. Aber ich bin mir ziemlich sicher, dass der Compiler die Rechte hat, ihn zu inline und/oder mehrfach zu berechnen. – ony

+2

Ich hatte das zuerst als mein Beispiel, aber ich konnte GHC nicht genug kitzeln, um das tatsächlich beobachtbar zu machen, daher dieses Beispiel. –

Verwandte Themen