Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there an identity function in Ruby?

I'm currently writing a Ruby class that provides a menu of base lambdas that can be mixed-and-matched to create a new set of lambdas. (it's an evolutionary algorithm that requires a lot of customizing of the fitness function depending on the dataset)

The configuration fire where this happens it full of stuff like this

function_from_modifier.(base_function, either.(modifier_from.(case),->(x){x}) )

The identity function ->(x){x} pops up several times in the configuration file, and it looks ugly, so I was wondering if there is a more elegant way of doing this. Is something like Elixir's &(&1) possible in Ruby?

like image 387
Timo Y Avatar asked Jan 26 '23 13:01

Timo Y


1 Answers

tl;dr summary: there is no identity function in the Ruby core or standard libraries. In fact, there are no functions (in the sense of pre-defined Proc instances) at all anywhere in the core or standard libraries.

First-class functions in Ruby are kind-of second-class (if that makes sense).

When Yukihiro "matz" Matsumoto first designed Ruby, he surveyed the standard libraries of other languages for uses of first-class and higher-order functions, and he found that the vast majority of uses were:

  • a single function argument
  • that is not stored, passed, or returned
  • that is only immediately invoked one or more times

A significant portion of higher-order functions where this is not true are control structures (e.g. if which takes a condition and two consequences), which however he wanted to model as built-in language constructs, not library functions.

Therefore, he decided to optimize Ruby for the common case that he identified, and created blocks.

Blocks are not first-class functions:

  • they aren't objects
  • you can't send messages to them
  • they can't be stored in variables
  • they can't be returned
  • they can't be freely passed as arguments, you can only pass at most one and only at a special place in the argument list

As a result, real (in the sense that they are actual objects) first-class functions (Procs) are in some sense second-class language features compared to blocks:

  • they are more expensive in memory
  • calling them is slower
  • they are more syntactically cumbersome to create

So, in essence, it is not surprising that you are running into limitations when trying to use Ruby the way you do: that's not what Ruby was designed for.

In the past, I used to carry around a helper library with constants such like this:

class Proc
  Id = -> x { x }
end

But I stopped doing that. If I want to use Ruby, I use Ruby as an OO language, if I want to do fancy FP, I use Haskell or Scala or Clojure or Racket or …

like image 82
Jörg W Mittag Avatar answered Jan 31 '23 08:01

Jörg W Mittag