K Combinator (C #, Scala)
Uso il combinatore K in Ruby abbastanza spesso, principalmente nelle pieghe quando l'operazione di piegatura viene eseguita attraverso un effetto collaterale piuttosto che un valore di ritorno, come in questo esempio:
some_collection.reduce(Hash.new(0)) {|acc, el| acc[el] += 1 }
Conta quante volte ogni elemento si verifica in some_collection
. Sfortunatamente, in realtà non funziona, poiché il blocco deve restituire il nuovo valore dell'accumulatore ad ogni iterazione, ma nelle assegnazioni di Ruby valutare il valore assegnato.
Quindi, devi restituire ecicamente il nuovo valore dell'accumulatore in questo modo:
some_collection.reduce(Hash.new(0)) {|acc, el| acc[el] += 1; acc }
Ma trovo il sequenziamento così esplicito brutto in questo stile funzionale-ish che usa le pieghe. Il combinatore K (chiamato Object#tap
in Ruby) al salvataggio:
some_collection.reduce(Hash.new(0)) {|acc, el| acc.tap { acc[el] += 1 }}
L'ho già perso un paio di volte in C # (principalmente perché per qualche motivo i mutatori di raccolta come List.Add
return void
invece di this
) e Scala, quindi mi porto dietro questo:
namespace GenericExtensions
{
public static class GenericExtensions
{
public static T Tap<T>(this T o, Action<T> f)
{
Contract.Requires(o != null);
Contract.Requires(f != null);
f(o);
return o;
}
public static T Tap<T>(this T o, Action f)
{
Contract.Requires(o != null);
Contract.Requires(f != null);
f();
return o;
}
}
}
e in Scala:
class Tap[T](o: T) {
def tap(f: T => Unit) = { f(o); o }
def tap(f: => Unit) = { f; o }
}
object Implicits { implicit def any2Tap[T](o: T) = new Tap(o) }
Funzione Identity (Ruby)
Qualcosa che mi manca in Ruby, è un modo ben definito per accedere alla funzione di identità. Haskell fornisce la funzione di identità con il nome di id
, Scala con il nome di identity
. Questo permette di scrivere codice come:
someCollection.groupBy(identity)
L'equivalente in Ruby è
some_collection.group_by {|x| x }
Non si stacca esattamente la lingua, vero?
La correzione è
IDENTITY = -> x { x }
some_collection.group_by(&IDENTITY)
ForEach (.NET)
Un altro metodo decisamente mancante in C #:
namespace IEnumerableExtensions
{
public static class IEnumerableExtensions
{
public static void ForEach<T>(this IEnumerable<T> xs, Action<T> f)
{
Contract.Requires(xs != null);
Contract.Requires(f != null);
foreach (var x in xs) f(x);
}
}
}