Domanda

mi chiedo perché scala.Option non ha un metodo come questo fold definito:

fold(ifSome: A => B , ifNone: => B)

equivalente a

map(ifSome).getOrElse(ifNone)

Non c'è di meglio che usare map + getOrElse?

È stato utile?

Soluzione

Si può fare:

opt foldLeft (els) ((x, y) => fun(x))

o

(els /: opt) ((x,y) => fun(x))

(Entrambe le soluzioni valuterà els per valore, che potrebbe non essere ciò che si desidera. Grazie a Rex Kerr per puntare a questo.)

Modifica

Ma che cosa si vuole veramente è di Scalaz catamorphism cata (in pratica un fold che non solo le maniglie il valore Some ma le mappe anche la parte None, che è quello che hai descritto)

opt.cata(fun, els)

definito come (dove value è il valore dell'opzione pimped)

def cata[X](some: A => X, none: => X): X = value match {
  case None => none
  case Some(a) => some(a)
}

, che è equivalente a opt.map(some).getOrElse(none).

Anche se devo sottolineare che si dovrebbe utilizzare solo cata quando è il modo ‘più naturale’ di esprimerlo. Ci sono molti casi in cui un semplice può bastare map-getOrElse, soprattutto quando si tratta potenzialmente concatenamento un sacco di maps. (Anche se si potrebbe anche catena funs con la composizione di funzione, ovviamente -. Dipende dal fatto che si vuole mettere a fuoco la composizione di funzione o il valore di trasformazione)

Altri suggerimenti

Personalmente trovo metodi come cata che prendono due chiusure come argomenti sono spesso strafare. Cosa si guadagna davvero in leggibilità oltre map + getOrElse? Pensate a un nuovo arrivato al codice: Cosa faranno fare della

opt cata { x => x + 1, 0 }

pensi davvero che questo è più chiaro che

opt map { x => x + 1 } getOrElse 0

In realtà direi che nessuno dei due è preferibile rispetto il buon vecchio

opt match {
  case Some(x) => x + 1
  case None => 0
}

Come sempre, c'è un limite in cui l'astrazione aggiuntivo non ti dà benefici e giri controproducente.

È stato infine aggiunto a Scala 2.10 , con la firma fold[B](ifEmpty: => B)(f: A => B): B.

Purtroppo, questo ha una conseguenza comune negativo: B viene dedotta per chiamate in base solamente sull'argomento ifEmpty, che è in pratica spesso più stretto. Per esempio. (Una versione corretta è già nella libreria standard, questo è solo per la dimostrazione)

 def toList[A](x: Option[A]) = x.fold(Nil)(_ :: Nil)

Scala sarà inferire B essere Nil.type invece di List[A] desiderato e si lamentano di non tornare f Nil.type. Invece, è necessario uno dei

 x.fold[List[A]](Nil)(_ :: Nil)
 x.fold(Nil: List[A])(_ :: Nil)

Questo rende fold non del tutto equivalente alla corrispondente match.

Come menzionato da Debilski, è possibile utilizzare OptionW.cata o fold di Scalaz. Come ha commentato Jason, parametri denominati rendono questo aspetto bello:

opt.fold { ifSome = _ + 1, ifNone = 0 }

Ora, se il valore che si desidera nel caso None è mzero per qualche Monoid[M] e si dispone di un f: A => M funzione per il caso Some, si può fare in questo modo:

opt foldMap f

opt map (_ + 1) getOrElse 0

diventa

opt foldMap (_ + 1)

Personalmente, penso che Option dovrebbe avere un metodo apply che sarebbe il catamorphism. In questo modo si può solo fare questo:

opt { _ + 1, 0 }

o

opt { some = _ + 1, none = 0 }

In realtà, questo sarebbe bello avere per tutte le strutture di dati algebrica.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top