Unclear about default value for OCaml argument - arguments

I am a bit unclear of what exactly will be the value of var_c in this function definition in OCaml. Is it assigning var_c a default value of the result of the function? Or a default value of Enum.peek var_c to var_c?
let rec read var_a ?(var_b = var_a) var_c = match Enum.peek var_c with
None -> None
...
Thanks for your help.

var_c does not have a default value in the snippet you posted. It is not optional and must be given as an argument. var_b does have a default value (namely the value of var_a).
match Enum.peek var_c with ... will be the result of the function. It is not the default value of anything.

Related

Check if method's parameter was set by user

Is there a way to check if the parameter of the method was set by the default value set in the method itself or by the user who called the method?
Here's what I want to do in my method, for example
def json_prop(key, value = nil)
json_data = {} if json_data.nil?
return json_data[key] if value.set_by_user? # i.e. User did not set value to nil himself
json_data[key] = value # Set to the value inserted by the user when calling the method
end
There is a standard trick to do this, and it relies on two features of the Ruby programming language:
The default argument value for an optional parameter is a Ruby expression and thus can contain any arbitrary Ruby code and
Local variables defined in the default argument value expression are in scope in the method's body.
Therefore, all we need to do is set a variable in the default argument value expression, and we know: if the variable is set, the default argument value expression was evaluated and thus no argument value was passed:
def json_prop(key, value = (no_value_set_by_user = true; nil))
json_data = {} if json_data.nil?
return json_data[key] if no_value_set_by_user
json_data[key] = value
end
or
def json_prop(key, value = (
no_value_set_by_user = true
nil
))
json_data = {} if json_data.nil?
return json_data[key] if no_value_set_by_user
json_data[key] = value
end

How to understand the '...' operator used with Boolean comparisons

select = []
0.upto 5 do |value|
select << value if (value==2)...(value==2)
end
p select # [2,3,4,5]
Can anyone tell me how to understand this code?
I learned something researching this because I've never seen the range operator used on boolean values. Apparently in this context its called a "flip flop" operator. Basically, the condition evaluates False until the first part of the conditional is True. Then it "flips" and evaluates True until the 2nd part evaluates True. In your example, the 2nd part will never evaluate to True as its already passed the valid condition of value == 2 therefore it will continue on with the range provided. You can see this flip-flopping in action if you change the 2nd condition to value == 4:
select = []
0.upto 5 do |value|
select << value if (value==2)...(value==4)
end
p select # [2,3,4]
Reference: http://nithinbekal.com/posts/ruby-flip-flop/

Getting the default value of named or optional parameter

I have a method that looks like this:
class A
def my_method(a: 'key value', b = 'opt value')
# ...
end
end
Using reflection, I can get the parameter names like this:
A.new.method(:my_method).parameters
# => [[:key, :a], [:opt, :b]]
How can I get the default values of these parameters without invoking my_method?
This is not possible. I can't find the thread right now, but matz has explicitly said that this is by design. The problem is that the default value is an arbitrary expression, and since everything in Ruby is an expression, it can be anything.
For example, what about this:
def foo(bar = if rand < 0.5 then Time.now else rand end)
What would your proposed method return here?
Basically, you have two choices:
Evaluate the default value expression. This means you will get some value, but that doesn't tell you much about what the real expression is.
Don't evaluate the default value expression, by packaging it up in a Proc. But there's no way to get the expression out of a Proc again.
So, either way, you don't actually get any useful information.

Why doesn't Array#each_with_object(0) work?

Why does using 0 as the argument in each_with_object not return the correct value:
[1,2,3].each_with_object(0) {|i,o| o += i }
# => 0
but using an empty array and reduce(:+) does?
[1,2,3].each_with_object([]) {|i,o| o << i }.reduce(:+)
# => 6
From documentation it says:
each_with_object(obj) → an_enumerator
Iterates the given block for each element with an arbitrary object given, and returns the initially given object.
If no block is given, returns an enumerator.
As Array is an the same initial object, but with modified values is being returned in this case.
If we see the code of each_with_object, It is:
# File activesupport/lib/active_support/core_ext/enumerable.rb, line 79
def each_with_object(memo)
return to_enum :each_with_object, memo unless block_given?
each do |element|
yield element, memo
end
memo
end
You can see, It don't modifies memo, so if memo is 0 and you change it in the code block, It will still return zero, but if you pass [] and change it inside code block, It will return array with values.
There is no Ruby bug in your examples, which means they are all correct.
In the first example, the argument 0 is the return value. In the second example, the argument (that appears to be [] initially) is the return value. Only in the latter, the argument had been modified, and ended up looking different from what it looked like at the beginning, but the identity of the object is retained.

Ruby block method help

I was trying to see if I could reconstruct the Array class' delete_if iterator as my own method in order to see if I understood methods and blocks correctly. Here is what I coded:
def delete_if(arr)
for x in 0...arr.length
if (yield arr[x])
arr[x]=arr[x+1,arr.length]
redo
end
end
end
arr = [0,1,2,3,4,5]
delete_if(arr) {|value| value % 2 == 0}
This resulted in an error saying that the % method could not be identified in the last line. I know that value is going to be an integer so I am not sure why it would say this error. Can someone please explain? Also, in Ruby in general, how can you be sure that someone passes the correct type into a method? What if the method is supposed to take a string but they pass in an integer -- how do you prevent that??
Thanks!
def delete_if arr
for x in 0...arr.length
return if x >= arr.length
if yield arr[x]
arr[x..-1] = arr[(x + 1)..-1]
redo
end
end
end
Things I fixed:
it's necessary to mutate the array, if all you do is assign to the parameter, your changes will be local to the method. And for that matter, you were assigning your calculated array object to an element of the original array, which was the immediate cause of the error message.
since the array may become shorter, we need to bail out at the (new) end
of course you could just use arr.delete_at x but I couldn't correct the slice assignment without keeping the code pattern

Resources