Dopo aver ascoltato l'ultimo podcast di Stack Overflow, il compattore Python di Peter Norvig mi ha incuriosito, così ho deciso di implementarlo in Scala se potessi esprimerlo bene nell'idioma Scala funzionale, e anche di vedere quante righe di codice Prenderei.Come posso approssimare Python o l'operatore per il confronto dei set in Scala?
Ecco l'intero problema. (Non confrontiamo ancora le righe di codice.)
(Due note: puoi eseguirlo nell'interprete di Scala, se lo desideri.Se hai bisogno di una copia di big.txt, o dell'intero progetto, è on GitHub.)
import scala.io.Source
val alphabet = "abcdefghijklmnopqrstuvwxyz"
def train(text:String) = {
"[a-z]+".r.findAllIn(text).foldLeft(Map[String, Int]() withDefaultValue 1)
{(a, b) => a(b) = a(b) + 1}
}
val NWORDS = train(Source.fromFile("big.txt").getLines.mkString.toLowerCase)
def known(words:Set[String]) =
{Set.empty ++ (for(w <- words if NWORDS contains w) yield w)}
def edits1(word:String) = {
Set.empty ++
(for (i <- 0 until word.length) // Deletes
yield (word take i) + (word drop (i + 1))) ++
(for (i <- 0 until word.length - 1) // Transposes
yield (word take i) + word(i + 1) + word(i) + (word drop (i + 2))) ++
(for (i <- 0 until word.length; j <- alphabet) // Replaces
yield (word take i) + j + (word drop (i+1))) ++
(for (i <- 0 until word.length; j <- alphabet) // Inserts
yield (word take i) + j + (word drop i))
}
def known_edits2(word:String) = {Set.empty ++ (for (e1 <- edits1(word);
e2 <- edits1(e1) if NWORDS contains e2) yield e2)}
def correct(word:String) = {
val options = Seq(() => known(Set(word)),() => known(edits1(word)),
() => known_edits2(word),() => Set(word))
val candidates = options.foldLeft(Set[String]())
{(a, b) => if (a.isEmpty) b() else a}
candidates.foldLeft("") {(a, b) => if (NWORDS(a) > NWORDS(b)) a else b}
}
In particolare, mi chiedo se c'è qualcosa più pulito che posso fare con la funzione correct
. Nel Python originale, l'implementazione è un po 'più pulito:
def correct(word):
candidates = known([word]) or known(edits1(word)) or
known_edits2(word) or [word]
return max(candidates, key=NWORDS.get)
A quanto pare in Python, un insieme vuoto valuterà a Boolean False
, in modo che solo il primo dei candidati per restituire un insieme non vuoto sarà valutata, salvataggio di chiamate potenzialmente costose su edits1
e known_edits2
.
L'unica soluzione che otterrei è la versione che vedete qui, dove vengono chiamate le funzioni anonime Seq
fino a quando non viene restituito uno Set
non vuoto, che è garantito l'ultimo.
Testate Scala così esperte, c'è un modo più sintatticamente conciso o migliore per farlo? Grazie in anticipo!
... e l'attesa per Daniel comincia. –
Non ha ancora risposto; Sono scioccata! Probabilmente avrà una fodera monotona che fa apparire entrambi i nostri frammenti come Perl. –
Mi rendo conto che l'argomento è piuttosto vago. Che cosa suggeriresti? Qualcosa come "Come posso approssimare Python o l'operatore per il confronto degli insiemi in Scala?" –