2014-12-19 16 views
5

Poniżej funkcji getRandomString generuje losowy ciąg z listy znaków:Jest to czysta funkcja w Scala

def genRandomInt(lb: Int, ub: Int) = { 
    val rnd = new scala.util.Random 
    lb + rnd.nextInt(ub) 
    }  
    def getRandomString(validChars: List[Char]) = { 

    val size = validChars.size 

    val random = new scala.util.Random 
    val stringBuilder = new StringBuilder 
    val rnd = genRandomInt(0, size) 
    val sb = new StringBuilder 

    for (i <- 0 to size - 1) { 
     val rnd = genRandomInt(0, size) 
     sb.append(validChars(rnd)) 
    } 

    sb.toString 
    }            //> getRandomString: (validChars: List[Char])String 

    val rs = getRandomString(('a' to 'j').toList) 
                //> rs : String = aghdjjhjge 

Is getRandomString przykładem czystej funkcji, gdyż nie zmienia stanu?

+3

„, jeśli jego argumentem nie zmienia się między wieloma połączeniami, a jego wynik nie ulegnie zmianie. " - Możesz pokazać przykład tego? Jestem prawie pewien, że to nieprawda, ale nie mogę tego przetestować, ponieważ twój kod się nie kompiluje. –

+0

@ Jörg W Mittag Twoje prawa wynik się zmieni, ive usunięte to zdanie. Ten kod nie jest referencyjny przezroczysty. Ten kod jest dla mnie kompilowany w arkuszu kalkulacyjnym przy użyciu Eclipse Kepler Scala w wersji 2.11 –

+0

'error: not found: value genRandomInt'. To wydaje się być metodą z wiązania Scala MATLAB? Ale nie mam MATLAB. –

Odpowiedz

8

Nie, ponieważ w rzeczywistości modyfikuje stan. new scala.util.Random ostatecznie wywołuje , który uzyskuje dostęp i modyfikuje statyczny (tj. Globalny), zmienny AtomicLong o nazwie seedUniquifier. Dlatego też, jeśli ta metoda zostanie wywołana wiele razy, wynik się zmieni.

Jest to dobry przykład tego, jak niewinnie wyglądające metody mogą ukrywać dostęp do globalnego stanu zmiennego, co byłoby zabronione w bardziej rygorystycznym języku funkcjonalnym, takim jak Haskell (choć takie podejście ma swoje własne problemy).

1

Nie, ponieważ new scala.util.Random().nextInt ... zwraca za każdym razem coś innego, co jest zrozumiałe przez Imm.

Niemniej jednak możesz po prostu przekazać nasienie, wtedy będzie to czysta funkcja, ponieważ za każdym razem zwróci ten sam losowy ciąg znaków. Możesz dodać seed jako parametr lub po prostu naprawić go w losowej metodzie ciągów.

Wreszcie zauważyłem, że napisałeś ogromną ilość kodu do wygenerowania losowego ciągu. Sugeruję, aby spojrzeć na ScalaCheck, który ma stosy przydatnych funkcji do generowania losowych rzeczy (dla testów jednostkowych), String pojawia się po rozpakowaniu.

Jeśli nie chcesz ciągnąć w bibliotece, można jeszcze zrobić, że kod znacznie bardziej zwięzły:

def randomString(fromChars: List[Char], length: Int): String = { 
    val rand = new Random(1234) // Now it's pure functional because the seed is fixed 
    val fromCharsSize = fromChars.size // to save us repeatedly counting 
    List.fill(length)(fromChars(rand.nextInt(fromCharsSize))).mkString 
} 

przestrzegać zwraca taką samą wartość za każdym razem

scala> randomString("asdf".toList, 10) 
res0: String = dsfafssdsa 

scala> randomString("asdf".toList, 10) 
res1: String = dsfafssdsa 
Powiązane problemy