I am getting my head around the functional model in Ruby and ran into a problem. I am able to successfully pass any given number of arguments to an arbitrary function as follows:
add = ->(x, y) { return x + y }
mul = ->(x, y) { return x * y }
def call_binop(a, b, &func)
return func.call(a, b)
end
res = call_binop(2, 3, &add)
print("#{res}\n") #5
res = call_binop(3, 4, &mul)
print("#{res}\n") #12
However, I am not able to pass an arbitrary number of functions:
dbl = ->(x) { return 2 * x }
sqr = ->(x) { return x * x }
def call_funccomp(a, &func1, &func2)
return func2.call(func1.call(a))
end
res = call_funccomp(3, &dbl, &sqr)
print("#{res}\n") #Expect 36 but compiler error
The compiler error is syntax error, unexpected ',', expecting ')'
I have already added both lambdas and procs to an array and then executed elements of the array, so I know I can get around this by passing such an array as an argument, but for simple cases this seems to be a contortion for something (I hope) is legal in the language. Does Ruby actually limit the number or lambdas one can pass in the argument list? It seems to have a reasonably modern, flexible functional model (the notation is a little weird) where things can just execute via a call method.
Does Ruby actually limit the number or lambdas one can pass in the argument list?
No, you can pass as many procs / lambdas as you like. You just cannot pass them as block arguments.
Prepending the proc with & triggers Ruby's proc to block conversion, i.e. your proc becomes a block argument. And Ruby only allows at most one block argument.
Attempting to call call_funccomp(3, &dbl, &sqr) is equivalent to passing two blocks:
call_funccomp(3) { 2 * x } { x * x }
something that Ruby doesn't allow.
The fix is to omit &, i.e. to pass the procs / lambdas as positional arguments:
dbl = ->(x) { 2 * x }
sqr = ->(x) { x * x }
def call_funccomp(a, func1, func2)
func2.call(func1.call(a))
end
res = call_funccomp(3, dbl, sqr)
print("#{res}\n")
There's also Proc#>> which combines two procs:
def call_funccomp(a, func1, func2)
(func1 >> func2).call(a)
end
Related
In Julia, I want to have a mutable struct with an attribute which type is a Function, this function will have arguments:
mutable struct Class_example
function_with_arguments::Function
some_attribute::Int
function Class_example() new() end
function Class_example(function_wa::Function, some_a::Int)
this = new()
this.function_with_arguments = function_wa
this.some_attribute = some_a
this
end
end
I also want to do an action on this mutable struct :
function do_action_on_class(Class::Class_example)
return Class.function_with_arguments(Class.some_attribute ,2.0, true)
end
Then I define a function that aims to be my class attribute :
function do_something_function(arg1::Int, arg2::Float64, arg3::Bool)
if arg2 < 5.0
for i in 1:arg1
# Do Something Interesting
#show arg3
end
end
return 1
end
Finally, function_whith_arguments will be launch a huge number of time in my whole project, this is only a minimal example, so I want all this code to be very quick. That's why I use #code_warntype according to Julia's documentation Performance Tips
However, #code_warntype tells me this
body::Any
15 1 ─ %1 = (Base.getfield)(Class, :function_with_arguments)::Function
getproperty
%2 = (Base.getfield)(Class, :some_attribute)::Int64
%3 = (%1)(%2, 2.0, true)::Any │
return %3
Here, ::Function and the two ::Any are in red, indicating Julia can improve the performance of the code with a better implementation. So what's this correct implementation ? How should I declare my attribute function_whith_arguments as a Function type in my mutable struct ?
Whole code compilable :
mutable struct Class_example
function_with_arguments::Function
some_attribute::Int
function Class_example() new() end
function Class_example(function_wa::Function, some_a::Int)
this = new()
this.function_with_arguments = function_wa
this.some_attribute = some_a
this
end
end
function do_action_on_class(Class::Class_example)
return Class.function_with_arguments(Class.some_attribute ,2.0, true)
end
function do_something_function(arg1::Int, arg2::Float64, arg3::Bool)
if arg2 < 5.0
for i in 1:arg1
# Do Something Interesting
#show arg3
end
end
return 1
end
function main()
class::Class_example = Class_example(do_something_function, 4)
#code_warntype do_action_on_class(class)
end
main()
This will be efficient (well inferred). Note that I only modified (and renamed) the type.
mutable struct MyClass{F<:Function}
function_with_arguments::F
some_attribute::Int
end
function do_action_on_class(Class::MyClass)
return Class.function_with_arguments(Class.some_attribute ,2.0, true)
end
function do_something_function(arg1::Int, arg2::Float64, arg3::Bool)
if arg2 < 5.0
for i in 1:arg1
# Do Something Interesting
#show arg3
end
end
return 1
end
function main()
class::MyClass = MyClass(do_something_function, 4)
#code_warntype do_action_on_class(class)
end
main()
What did I do?
If you care about performance, you should never have fields of an abstract type, and isabstracttype(Function) == true. What you should do instead is parameterize on that fields type (F above, which can be any function. Note that isconcretetype(typeof(sin)) == true). This way, for any particular instance of MyCall the precise concrete type of every field is known at compile time.
Irrelevant for performance but: There is no need for a constructor that simply assigns all the arguments to all the fields. Such a constructor is defined by default implicitly.
You can read more about parametric types here.
On a side note, what you are doing looks a lot like trying to write OO-style in Julia. I'd recommend to not do this but instead use Julia the Julia way using multiple dispatch.
+ is a method.
5 + 3 #=> 8
5.+(3) #=> 8
Can anyone show me the method definition of +?
Here's the source of Integer#+ for 2.5.0:
VALUE
rb_int_plus(VALUE x, VALUE y)
{
if (FIXNUM_P(x)) {
return fix_plus(x, y);
}
else if (RB_TYPE_P(x, T_BIGNUM)) {
return rb_big_plus(x, y);
}
return rb_num_coerce_bin(x, y, '+');
}
It's usually easy to find it in documentation:
https://ruby-doc.org/core-2.5.0/Integer.html#method-i-2B
Keep in mind what Jörg W Mittag pointed out - there are number of + methods and for example method + defined on what's returned by 4.4 literal will differ, because it's Float, not Integer.
You also may have noticed that it's C, not Ruby. It's because Ruby interpreter, MRI, is written in C, so no wonder that the core functions of this language (like Integer class and its methods) are also written in C.
Just for your information, there is a gem that provides documentation/source code for Ruby in shell : pry-doc
It is a plug-in for pry (another ruby shell)
It's very useful and helped me every day. I really recommend it for any ruby project.
Your case is pretty particular and gave me a headache trying to get the + method source. I learned that when looking for operator (+, -, ==, <<, ...) source code or documentation, you have to put a . in front the operator.
Example
pry(main)> ? [].==
From: array.c (C Method):
Owner: Array
Visibility: public
Signature: ==(arg1)
Number of lines: 7
Equality --- Two arrays are equal if they contain the same number of elements and if each element is equal to (according to Object#==) the corresponding element in other_ary.
[ "a", "c" ] == [ "a", "c", 7 ] #=> false
Below is how to use it in your case
[1] pry(main)> x = 5
=> 5
[2] pry(main)> show-source x.+
From: numeric.c (C Method):
Owner: Integer
Visibility: public
Number of lines: 11
VALUE
rb_int_plus(VALUE x, VALUE y)
{
if (FIXNUM_P(x)) {
return fix_plus(x, y);
}
else if (RB_TYPE_P(x, T_BIGNUM)) {
return rb_big_plus(x, y);
}
return rb_num_coerce_bin(x, y, '+');
}
[3] pry(main)> x = 5.0
=> 5.0
[4] pry(main)> $ x.+
From: numeric.c (C Method):
Owner: Float
Visibility: public
Number of lines: 16
static VALUE
flo_plus(VALUE x, VALUE y)
{
if (RB_TYPE_P(y, T_FIXNUM)) {
return DBL2NUM(RFLOAT_VALUE(x) + (double)FIX2LONG(y));
}
else if (RB_TYPE_P(y, T_BIGNUM)) {
return DBL2NUM(RFLOAT_VALUE(x) + rb_big2dbl(y));
}
else if (RB_TYPE_P(y, T_FLOAT)) {
return DBL2NUM(RFLOAT_VALUE(x) + RFLOAT_VALUE(y));
}
else {
return rb_num_coerce_bin(x, y, '+');
}
}
Here is the implementation in Opal:
def +(other)
%x{
if (other.$$is_number) {
return self + other;
}
else {
return #{__coerced__ :+, other};
}
}
end
You may have noticed that it is Ruby with embedded ECMAScript which in turn has Ruby embedded in it. Opal is a compiler for the ECMAScript platform, so some low-level methods are partially implemented in ECMAScript for performance reasons.
I thought '3.0'.to_d.div(2) is same as '3.0'.to_d / 2, but the former return 1 while latter returns 1.5.
I searched by def / in Bigdecimal's github repository, but I couldn't find it.
https://github.com/ruby/bigdecimal/search?utf8=%E2%9C%93&q=def+%2F&type=Code
Where can I find the definition? And which method is a equivalent to / in Bigdecimal?
In Float there is a fdiv method. Is there similar one in Bigdecimal?
You can find it in the source code of the bigdecimal library, in the repository you linked to. On line 3403 of ext/bigdecimal/bigdecimal.c, BigDecimal#/ is bound to the function BigDecimal_div:
rb_define_method(rb_cBigDecimal, "/", BigDecimal_div, 1);
This function looks like this:
static VALUE
BigDecimal_div(VALUE self, VALUE r)
/* For c = self/r: with round operation */
{
ENTER(5);
Real *c=NULL, *res=NULL, *div = NULL;
r = BigDecimal_divide(&c, &res, &div, self, r);
if (!NIL_P(r)) return r; /* coerced by other */
SAVE(c); SAVE(res); SAVE(div);
/* a/b = c + r/b */
/* c xxxxx
r 00000yyyyy ==> (y/b)*BASE >= HALF_BASE
*/
/* Round */
if (VpHasVal(div)) { /* frac[0] must be zero for NaN,INF,Zero */
VpInternalRound(c, 0, c->frac[c->Prec-1], (BDIGIT)(VpBaseVal() * (BDIGIT_DBL)res->frac[0] / div->frac[0]));
}
return ToValue(c);
}
This is because BigDecimal#div takes a second argument, precision, which defaults to 1.
irb(main):017:0> '3.0'.to_d.div(2, 2)
=> 0.15e1
However, when / is defined on BigDecimal,
rb_define_method(rb_cBigDecimal, "/", BigDecimal_div, 1);
They used 1 for the # of arguments, rather than -1 which means "variable number of arguments". So BigDecimal#div thinks it takes one required argument and one optional argument, whereas BigDecimal#/ takes one required argument and the optional arg is ignored. Because the optional argument is ignored, it's not initialized correctly, it gets an empty int or 0.
This may be considered a bug. You should consider opening an issue with the ruby devs.
I am currently just trying to wrap my head around this example question. I don't understand the syntax of it. I don't understand the point of i and how it relates to result
def pow(base, exponent)
result = 1
i = 1
while i <= exponent
result = result * base
i += 1
end
result
end
Any explanation much appreciated!!
while need a do while(i <= exponent) do
i is a counter, you can replace the while for
exponent.times { result = result * base }
this code will execute the number (exponent) times the content of { }
And the result on end is the result of function, in ruby if you don't put a return clause will return the last line executed
We've been profiling our code recently and we've come across a few annoying hotspots. They're in the form
assert(a == b, a + " is not equal to " + b)
Because some of these asserts can be in code called a huge amount of times the string concat starts to add up. assert is defined as:
def assert(assumption : Boolean, message : Any) = ....
why isn't it defined as:
def assert(assumption : Boolean, message : => Any) = ....
That way it would evaluate lazily. Given that it's not defined that way is there an inline way of calling assert with a message param that is evaluated lazily?
Thanks
Lazy evaluation has also some overhead for the function object created. If your message object is already fully constructed (a static message) this overhead is unnecessary.
The appropriate method for your use case would be sprintf-style:
assert(a == b, "%s is not equal to %s", a, b)
As long as there is a speciaized function
assert(Boolean, String, Any, Any)
this implementation has no overhead or the cost of the var args array
assert(Boolean, String, Any*)
for the general case.
Implementing toString would be evaluated lazily, but is not readable:
assert(a == b, new { override def toString = a + " is not equal to " + b })
It is by-name, I changed it over a year ago.
http://www.scala-lang.org/node/825
Current Predef:
#elidable(ASSERTION)
def assert(assertion: Boolean, message: => Any) {
if (!assertion)
throw new java.lang.AssertionError("assertion failed: "+ message)
}
Thomas' answer is great, but just in case you like the idea of the last answer but dislike the unreadability, you can get around it:
object LazyS {
def apply(f: => String): AnyRef = new {
override def toString = f
}
}
Example:
object KnightSpeak {
override def toString = { println("Turned into a string") ; "Ni" }
}
scala> assert(true != false , LazyS("I say " + KnightSpeak))
scala> println( LazyS("I say " + KnightSpeak) )
Turned into a string
I say Ni
Try: assert( a==b, "%s is not equals to %s".format(a,b))
The format should only be called when the assert needs the string. Format is added to RichString via implicit.