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 anziché un valore di ritorno, come in questo esempio:
some_collection.reduce(Hash.new(0)) {|acc, el| acc[el] += 1 }
Questo conta la frequenza con cui ogni elemento si presenta 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 si valuta il valore assegnato.
Quindi, devi restituire esplicitamente il nuovo valore dell'accumulatore in questo modo:
some_collection.reduce(Hash.new(0)) {|acc, el| acc[el] += 1; acc }
Ma trovo brutto questo sequenziamento esplicito in questo stile funzionale usando le pieghe. Il combinatore K (chiamato Object#tap
in Ruby) in soccorso:
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 ragione 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 identità (Ruby)
Qualcosa che mi manca in Ruby, è un modo ben chiamato per accedere alla funzione identità. Haskell fornisce la funzione di identità con il nome di id
, Scala con il nome di identity
. Ciò consente di scrivere codice come:
someCollection.groupBy(identity)
L'equivalente in Ruby è
some_collection.group_by {|x| x }
Non esce esattamente dalla lingua, vero?
La soluzione è
IDENTITY = -> x { x }
some_collection.group_by(&IDENTITY)
ForEach (.NET)
Un altro metodo gravemente 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);
}
}
}