Search code examples
rubyevalfirst-class-functions

Pass top-level function as callable to map


To be clear, I recognize that eval is evil, this is not for production code. That said, I'm trying to figure out if I can, for golfing purposes, shorten:

$*.map{eval _1}

any further, in much the same way that:

$*.map{|x|x.to_i}
# and
$*.map{_1.to_i}

can shorten to:

$*.map(&:to_i)

Python's first class functions make this easy; a listcomp like:

[eval(x)for x in sys.argv[1:]]

can shorten to:

[*map(eval,sys.argv[1:])]

because eval is a first-class function, and without parentheses it isn't called. But I've tried everything I can think of to suppress eval trying to run before being passed, e.g. $*.map(&eval), $*.map(:eval), and variations thereof, and it never works (because it calls eval with no arguments, or passes something that does not act as the eval function).

It's possible this can't be golfed, but I'm curious if there is any way, to get a direct reference to eval (not create some new custom Proc or lambda or the like that happens to invoke it internally) that can be passed around as an argument?

(To be clear, this isn't an actual code golf challenge, so I believe it remains on-topic for StackOverflow; I happen to want to do this for golf, but being able to convert top-level functions to first-class objects to pass them around is useful in some cases outside of golfing)


Solution

  • eval is a method in Kernel like most of the other things in Ruby that are "methods that pretend to be functions" so you can use Object#method to get a reference to it. Then use & to to convert that Method to a Proc:

    $*.map(&method(:eval))
    

    So method(:eval) is your "direct reference" to eval. But you still have to call #to_proc to get something that #map will be happy with.

    Maybe not really great for golf due to the length of method but I can't think of anything else.