Combinador K (C #, Scala)
Eu uso o combinador K em Ruby com bastante frequência, principalmente em dobras quando a operação de dobra é realizada através de um efeito colateral ao invés de um valor de retorno, como neste exemplo:
some_collection.reduce(Hash.new(0)) {|acc, el| acc[el] += 1 }
Isso conta com que frequência cada elemento ocorre some_collection
. Infelizmente, na verdade não funciona, pois o bloco precisa retornar o novo valor do acumulador a cada iteração, mas nas atribuições do Ruby é avaliado o valor atribuído.
Portanto, você deve retornar explicitamente o novo valor do acumulador assim:
some_collection.reduce(Hash.new(0)) {|acc, el| acc[el] += 1; acc }
Mas acho esse seqüenciamento explícito feio nesse estilo funcional usando dobras. O combinador K (chamado Object#tap
em Ruby) para o resgate:
some_collection.reduce(Hash.new(0)) {|acc, el| acc.tap { acc[el] += 1 }}
Eu já perdi algumas vezes em C # (principalmente porque, por algum motivo, mutadores de coleção, como List.Add
return em void
vez de this
) e Scala, então eu carrego isso:
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 em 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) }
Função de identidade (Ruby)
Algo que estou sentindo falta no Ruby, é uma maneira bem nomeada de acessar a função de identidade. Haskell fornece a função de identidade com o nome de id
, Scala com o nome de identity
. Isso permite escrever código como:
someCollection.groupBy(identity)
O equivalente em Ruby é
some_collection.group_by {|x| x }
Não sai exatamente da língua, pois não?
A correção é
IDENTITY = -> x { x }
some_collection.group_by(&IDENTITY)
ForEach (.NET)
Outro método extremamente ausente em 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);
}
}
}