Eine der traurigen Fakten von Scala ist, dass Aliase vom rekursiven Typ nicht unterstützt werden. die folgenden Aktionen ausführen in der REPL ergibt folgendes:
scala> type WalkFn = Function[Int, WalkFn]
<console>:7: error: illegal cyclic reference involving type WalkFn
type WalkFn = Function[Int, WalkFn]
^
Ein weiterer Hinweis ist, dass Scala ermöglicht es Ihnen nicht Werte, die durch Bezugnahme zu ändern (in der Regel verpönt, ja verabscheut ganz in der funktionalen Programmierung-Paradigma).
Allerdings nicht bestürzt! Es gibt andere Möglichkeiten. Eigenschaften können selbstreferentiell sein und Funktionen sind einfach Klassen in Scala. So können wir das generische rekursive WalkFn mit Merkmalen modellieren. Außerdem können wir unveränderliche Werte annehmen und unsere Funktion den nächsten Fortschritt zurückgeben, anstatt einen Parameter durch Referenz zu verändern.
Da der folgenden enthält zyklische Referenzen (WalkForward -> WalkBackward, WalkBackward -> WalkForward, etc.), müssen Sie :paste
in das scala REPL
vor dem Ausführen des folgenden Beispiels (so der Scala-Compiler alle kompiliert eingeben 3 Walk{Forward,Backward,Equal}
Implementierungen in einem Schritt
Erstens:.
$ scala
Welcome to Scala version 2.11.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_05).
Type in expressions to have them evaluated.
Type :help for more information.
scala> :paste
// Entering paste mode (ctrl-D to finish)
Nun fügen Sie den Code:
import scala.util.Random
object Helpers {
def pickRandom[A](items: A*) =
items(Random.nextInt(items.length))
}
trait WalkFn extends (Int => (Int, WalkFn)) {}
object WalkForward extends WalkFn {
def apply(i: Int) =
(i + Random.nextInt(6),
Helpers.pickRandom(WalkEqual, WalkBackward))
}
object WalkEqual extends WalkFn {
def apply(i: Int) =
(i + (Random.nextInt(7) - 3),
Helpers.pickRandom(WalkForward, WalkBackward))
}
object WalkBackward extends WalkFn {
def apply(i: Int) =
(Random.nextInt(6) - 3,
Helpers.pickRandom(WalkEqual, WalkForward))
}
def doWalk(count: Int, walkFn: WalkFn = WalkEqual, progress: Int = 0): Unit =
if (count > 0) {
val (nextProgress, nextStep) = walkFn(progress)
println(nextProgress)
doWalk(count - 1, nextStep, nextProgress)
}
doWalk(20)
Dann, per Anweisungen, drücken Sie ctrl-D
.
Genießen Sie die funktionale betrunkene Staffelung!
Nizza Antwort, aber (nicht * doch * mit Scala vertraut zu sein): Wozu brauchst du das 'Helfer'-Objekt? Ist es nur ein Namespace, oder verhindert eine Konvention, dass Sie eine "Definition" auf oberster Ebene machen? – Bergi
@Bergi alle 'def''s sind Methoden in scala (sie werden explizit/implizit in function-Objekte durch Eta-Expansion umgewandelt). Also sollte jede Methode innerhalb eines Objekts platziert werden. Übrigens erstellt Scala REPL (und der eingebaute Interpreter selbst) ein synthetisches Objekt, so dass Sie Methoden innerhalb der REPL-Schleife definieren können, aber Leute verwenden normalerweise Objekte, um Code bereit zu machen, von scalac ohne Änderungen kompiliert zu werden. – dk14