2014-10-04 16 views
6

Nelle varie Lisps, è possibile per me creare una successione di funzioni come se fossero appena stati i valori normali:Come definire un elenco di funzioni della stessa arity in Scala?

(def ops [+ - * /]) 

Quali Posso quindi scorrere, ancora una volta, come se fossero solo i valori normali :

(doseq [op ops] // (doseq (op ops) is like for (op <- ops) in scala 
    (println (op 1 2 3 4))) 

Ora, ho provato un paio di cose in Scala, tutti loro mancanza:

scala> List(+, -, *, /) 
<console>:1: error: illegal start of simple expression 
     List(+, -, *, /) 
      ^

scala> List[Double => Double](+, -, *, /) 
<console>:1: error: illegal start of simple expression 
     List[Double => Double](+, -, *, /) 
          ^

scala> List[Double => Double](+_, -_, *_, /_) 
<console>:8: error: not found: value * 
       List[Double => Double](+_, -_, *_, /_) 
              ^
<console>:8: error: not found: value/
       List[Double => Double](+_, -_, *_, /_) 
               ^

Allora, qual è la procedura corretta di definire un elenco di funzioni/operatori in Scala?

+0

ci sono buone risposte qui sotto, ma, come si può vedere, è possibile definire in modo solo * stesse funzioni tipizzati *. Se vuoi memorizzare diverse funzioni digitate devi usare * strutture eterogenee * (lista per esempio). – DaunnC

+0

@DaunnC ti dispiacerebbe elaborare l'uso di * utilizzare strutture eterogenee * in un'altra risposta alla domanda? Apprezzerei. –

risposta

11

Il problema è che queste funzioni sono operatori binari, cioè prendono due operandi e ne restituiscono uno. Quindi, è necessario utilizzare:

List[(Double, Double) => Double](_ + _, _ - _, _ * _, _/_) 
1

In Scala, la maggior parte degli operatori di livello valore sono in realtà metodi unario grado (forse tutti sono, non so se ci sono counterexmaples). Quindi, quando parli, ad esempio, di due valori di tipo Double, ti stai davvero riferendo a a method del primo valore che assume il secondo valore come parametro. La nota sintassi dell'operatore infisso is just sugar. In altre parole,

scala> 5.7 + 6.3 
res0: Double = 12.0 

è in realtà solo una bella scorciatoia per:

scala> 5.7.+(6.3) 
res1: Double = 12.0 

As @bluenote10 already mentioned, è possibile catturare questi operatori con la creazione di funzione anonima che prende sia la prima istanza e il suo operando come parametri e restituisce il risultato del metodo +:

scala> (lhs: Double, rhs: Double) => lhs + rhs 
res2: (Double, Double) => Double = <function2> 

O come in @ di bluenote10 esempio, se il tipo può essere dedotto (come in un elenco con il t ipo condizione), è possibile utilizzare la sintassi di bella sottolineatura:

scala> val doublePlus: (Double, Double) => Double = _ + _ 
doublePlus: (Double, Double) => Double = <function2>