Reputation: 2206
I'd like to see if a proc call with the same arguments will give the same results every time. pureproc
called with arguments is free, so every time I call pureproc(1,1)
, I'll get the same result. dirtyproc
called with arguments is bound within its environment, and thus even though it has the same arity as pureproc
, its output will depend on the environment.
ruby-1.9.2-p136 :001 > envx = 1 => 1 ruby-1.9.2-p136 :003 > pureproc = Proc.new{ |a,b| a+b } => # ruby-1.9.2-p136 :004 > dirtyproc = Proc.new{ |a,b| a+b+envx }
How can I programmatically determine whether a called proc or a method is free, as defined by only being bound over the variables that must be passed in? Any explanation of bindings, local variables, etc would be welcome as well.
Upvotes: 1
Views: 103
Reputation: 168199
Probably you can parse the source using some gem like sourcify, take out all the tokens, and check if there is anything that is a variable. But note that this is a different concept from the value of the proc/method call being constant. For example, if you had things like Time.now
or Random.new
in your code, that does not require any variable to be defined, but will still vary every time you call. Also, what would you want to be the case when a proc has envx - envx
? That will remain constant, but will still affect the code in the sense that it will return an error unless envx
is defined.
Upvotes: 1
Reputation: 66837
Hm, tricky. There's the parameters
method that tells you about expected arguments (note how they are optional cause you are using a procs, not lambdas).
pureproc.parameters
=> [[:opt, :a], [:opt, :b]]
dirtyproc.parameters
=> [[:opt, :a], [:opt, :b]]
As for determining whether or not one of the closed over variables are actually used to compute the return value of the proc, walking the AST comes to mind (there are gems for that), but seems cumbersome. My first idea was something like dirtyproc.instance_eval { local_variables }
, but since both closures close over the same environment, that obviously doesn't get you very far...
The overall question though is: if you want to make sure something is pure, why not make it a proper method where you don't close over the environment in the first place?
Upvotes: 0