Combinador K (C #, Scala)
Utilizo el combinador K en Ruby con bastante frecuencia, principalmente en pliegues cuando la operación de plegado se realiza a través de un efecto secundario en lugar de un valor de retorno, como en este ejemplo:
some_collection.reduce(Hash.new(0)) {|acc, el| acc[el] += 1 }
Esto cuenta con qué frecuencia ocurre cada elemento some_collection
. Desafortunadamente, en realidad no funciona, ya que el bloque debe devolver el nuevo valor del acumulador en cada iteración, pero en Ruby las asignaciones evalúan el valor asignado.
Por lo tanto, debe devolver de manera explícita el nuevo valor del acumulador de esta manera:
some_collection.reduce(Hash.new(0)) {|acc, el| acc[el] += 1; acc }
Pero considero que esa secuencia explícita es fea en este estilo funcional usando pliegues. El combinador K (llamado Object#tap
en Ruby) al rescate:
some_collection.reduce(Hash.new(0)) {|acc, el| acc.tap { acc[el] += 1 }}
Ya lo he perdido un par de veces en C # (principalmente porque, por alguna razón, los mutadores de colección como List.Add
return en void
lugar de this
) y Scala, así que llevo esto:
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;
}
}
}
y en 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) }
Función de identidad (Ruby)
Algo que me falta en Ruby, es una forma muy bien nombrada de acceder a la función de identidad. Haskell proporciona la función de identidad bajo el nombre de id
, Scala bajo el nombre de identity
. Esto le permite a uno escribir código como:
someCollection.groupBy(identity)
El equivalente en Ruby es
some_collection.group_by {|x| x }
No sale exactamente de la lengua, ¿verdad?
La solución es
IDENTITY = -> x { x }
some_collection.group_by(&IDENTITY)
ForEach (.NET)
Otro método que falta en 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);
}
}
}