2010-11-25 30 views
7

Je vais commencer le processus.Quels modèles courants/solutions ont été établis dans Scala pour les problèmes fréquemment rencontrés

Étant donné une séquence d'éléments, dont certains peuvent être contenus plusieurs fois, une exigence typique consiste à les compter - sous la forme d'un comptage ou d'un histogramme.

La solution est souvent citée:

ss.groupBy(identity).mapValues(_.size) 

Alors que d'autres solutions existent pour des problèmes similaires fréquemment rencontrés à Scala?

Répondre

3

Utiliser Monoid s ou Numeric s pour définir des opérations sensibles pour des classes riches, en utilisant des implicits si nécessaire.

case class Money(ccy: Currency, amount : BigDecimal) { 
    def +(that : Money) = { 
    require(this.currency == that.curency) 
    copy(amount = this.amount + that.amount) 
    } 
    def abs = copy(amount = amount.abs) 
} 

Alors disons que j'ai une collection de Money « s et je veux les résumer:

val turnover = trades.map(_.usdValue.abs).∑ //no implicit monoid :-(

Mais pour ce faire, je dois avoir un Monoid implicite. Mais bien sûr, une zéro valeur pour un Money n'a de sens que si j'ai de la monnaie déjà!

implicit def CurrencyMonoid(implicit currency : Currency) = new Monoid[Currency] { 
    def zero = Money(currency, 0) 
    def append(m1 : Money, m2 : Money) = m1 + m2 
} 

Alors maintenant Scala utilisera ces deux implicits:

implicit val usd = Currency.USD 
val turnover = trades.map(_.usdValue.abs).∑ //yay for monoids :-) 
+0

J'aime celui-ci le plus! C'est ma question, donc je suis autorisé à être subjectif :) –

3

J'ai manqué plusieurs fois un moyen de générer un produit cartésien pour les collections Scala. Dans Haskell vous pouvez écrire

import Control.Applicative 
(,) <$> [1,2,3] <*> ["a","b"] 

-- [(1,"a"),(1,"b"),(2,"a"),(2,"b"),(3,"a"),(3,"b")] 

La solution Scala

for(x <- List(1,2,3); y <- List("a","b")) yield (x,y) 

est trop maladroite.

+4

scalaz: '(Liste (1, 2, 3) | @ | List ("a", "b")) ((_, _)) ' – Debilski

+1

Ou scalaz:' (xs ⊛ ys) {× (_) (_)} 's'il en est ainsi –

4

Non pas que je suis à nouveau frapper le même tambour, mais ...

Une solution pour le problème où nous avons un certain nombre de processus qui peut produire une sortie réussie, ou échouer avec un certain message d'erreur. Le but est d'agréger les résultats positifs, si tous les processus produisent un succès et si un ou plusieurs échoue, d'agréger tous les messages d'erreur.

Ceci peut être résolu par scalaz validation: tout d'abord, la configuration des importations

scala> import scalaz._; import Scalaz._ 
import scalaz._ 
import Scalaz._ 

Maintenant, nous allons définir nos "processus"

scala> def fooI(s : String) : ValidationNEL[Exception, Int] = s.parseInt.liftFailNel 
fooI: (s: String)scalaz.Scalaz.ValidationNEL[Exception,Int] 

scala> def fooF(s : String) : ValidationNEL[Exception, Float] = s.parseFloat.liftFailNel 
fooF: (s: String)scalaz.Scalaz.ValidationNEL[Exception,Float] 

scala> def fooB(s : String) : ValidationNEL[Exception, Boolean] = s.parseBoolean.liftFailNel 
fooB: (s: String)scalaz.Scalaz.ValidationNEL[Exception,Boolean] 

utiliser maintenant Applicative pour agréger les échecs/succès:

scala> def attempt(ss : String*) = (fooI(ss(0)) <|**|> (fooF(ss(1)), fooB(ss(2)))) match { 
| case Success((i, f, b)) => println("Found " + i + " " + f + " " + b) 
| case Failure(es)  => es foreach println 
| } 
attempt: (ss: String*)Unit 

Maintenant, nous allons essayer de quelques échecs:

scala> attempt("a", "b", "true") 
java.lang.NumberFormatException: For input string: "a" 
java.lang.NumberFormatException: For input string: "b" 

Maintenant, nous allons essayer de succès:

scala> attempt("1", "2.3", "false") 
Found 1 2.3 false 
2

Si certaines conditions cond tient retour Some(x), sinon retourner None:

Some(x) filter cond 

[ ramassé à partir du message de Paul Phillips sur la liste de diffusion]

3

Shamelessly volé de la réponse de oxbow_lakes à cette question: Instantiating a case class from a list of parameters

appel d'une méthode/fonction à l'aide d'un tuple pour fournir les arguments:

case class Foo(a: Int, b: String, c: Double) 
(Foo.apply _).tupled apply (1, "bar", 3.14) 

Ceci peut être utilisé pour toute fonction.

1

Parfois, vous devez utiliser tout au lieu de pour, et souvent vous êtes des résultats collecte:

val buf = new Listbuffer[Int] 
while(cond()) { 
    val x = fancyStuff() 
    buf += calculation(x) 
} 

Je pense il serait très utile d'avoir pour while la même possibilité de "céder" quelque chose comme pour for, en enlevant quelques bavures sur le bord entre impératif et fonct style ionique:

val buf = while(cond()) { 
    val x = fancyStuff() 
} yield calculation(x)