Is 'clamp' with two positional arguments a common convention? - math

Someone submitted a patch to a project I work on that adds a math clamp function, supporting:
clamp(number): where min=0.0, max=1.0
clamp(number, min): where max=1.0
clamp(number, min, max).
Is clamp(number, min) a convention? It's not something I've seen before.

Related

Pipe with additional Arguments

I read in several places that pipes in Julia only work with functions that take only one argument. This is not true, since I can do the following:
function power(a, b = 2) a^b end
3 |> power
> 9
and it works fine.
However, I but can't completely get my head around the pipe. E.g. why is this not working?? :
3 |> power()
> MethodError: no method matching power()
What I would actually like to do is using a pipe and define additional arguments, e.g. keyword arguments so that it is actually clear which argument to pass when piping (namely the only positional one):
function power(a; b = 2) a^b end
3 |> power(b = 3)
Is there any way to do something like this?
I know I could do a work-around with the Pipe package, but to honest it feels kind of clunky to write #pipe at the start of half of the lines.
In R the magritrr package has convincing logic (in my opinion): it passes what's left of the pipe by default as the first argument to the function on the right - I'm looking for something similar.
power as defined in the first snippet has two methods. One with one argument, one with two. So the point about |> working only with one-argument methods still holds.
The kind of thing you want to do is called "partial application", and very common in functional languages. You can always write
3 |> (a -> power(a, 3))
but that gets clunky quickly. Other language have syntax like power(%1, 3) to denote that lambda. There's discussion to add something similar to Julia, but it's difficult to get right. Pipe is exactly the macro-based fix for it.
If you have control over the defined method, you can also implement methods with an interface that return partially applied versions as you like -- many predicates in Base do this already, e.g., ==(1). There's also the option of Base.Fix2(power, 3), but that's not really an improvement, if you ask me (apart from maybe being nicer to the compiler).
And note that magrittrs pipes are also "macro"-based. The difference is that argument passing in R is way more complicated, and you can't see from outside whether an argument is used as a value or as an expression (essentially, R passes a thunk containing the expression and a pointer to the parent environment, and automatically evaluates and caches it if you use it as a value; see substitute)

Julia convention for optional arguments

Say I have a function such as f(x,y) but the y parameter is optional. What is the preferred way to set y as an optional argument? One option that works for me:
function f(x, y=nothing)
# do stuff
if y == nothing
# do stuff
else
# do stuff
end
# do stuff
end
But is this the preferred way? I can't set y to a single default value to use in calculation, as there are a number of calculations that are done differently when y is nothing. I could also just have separate functions f(x) and f(x,y) but that seems like too much code duplication.
This is fine. Note that optional arguments cause dispatch. This means that the if y == nothing (or equivalently, if typeof(y) <: Void), will actually compile away. You'll get two different functions which depend on whether the user gives a value or not. So in the end, the if statement compiles away and it's perfectly efficient to do this.
I will note that the same is not currently true for keyword arguments.
Another way to do this is to have two methods:
f(x)
and
f(x,y)
Whether two methods is nicer than 1 method with an if depends on the problem. Since the if will compile away using type information, there's no difference between these two approaches other than code organization.

Hybrid handler for dplyr

I'm writing an hybrid handler for dplyr, and I'm wondering two things about the code in dplyr.cpp:
The option na.rm is used as a template and not passed as a parameter to the classes Sd, Var, Sum etc. What's the reason?
What does the line TAG(arg3) == R_NaRmSymbol (line 54) mean?
Although I'm not the author of the code, here's my best guesses at answers to your questions:
The option na.rm is used as a template and not passed as a parameter to the classes Sd, Var, Sum etc. What's the reason?
Likely for run-time efficiency -- dplyr tries to move computation from run-time to compile-time when possible. This is often accomplished through template usage.
What does the line TAG(arg3) == R_NaRmSymbol (line 54) mean?
Nodes in an R pairlist have a TAG attribute, which usually refers to the name of the formal. Hence, dplyr uses that to find the formal with the name na.rm. R caches many of the often-used symbols in src/main/names.c -- you should see NaRmSymbol in there.
So, effectively, the code finds the actual argument value associated with the formal na.rm, and does stuff based on its truthiness.

R: List of base Math functions

I want to get a list of available math functions without looking in index. I tried ls(), methods(), lsf() commands. I could not figure it out.
This will get you started, but I don't know how to identify "math functions" in base. You could run this, copy to Excel and sort as you wish to have a set:
lsf.str("package:base")
See ?Math for mathematics functions:
Group "Math":
abs, sign, sqrt, floor, ceiling, trunc, round, signif
exp, log, expm1, log1p, cos, sin, tan, cospi, sinpi, tanpi, acos,
asin, atan
cosh, sinh, tanh, acosh, asinh, atanh
lgamma, gamma, digamma, trigamma
cumsum, cumprod, cummax, cummin
Members of this group dispatch on x. Most members accept only one
argument, but members log, round and signif accept one or two
arguments, and trunc accepts one or more.
Have you looked at
Advanced R, Vocabulary (by Hadley Wickham)?
http://adv-r.had.co.nz/Vocabulary.html
That gives you the basic math functions in 'The basics' section plus much more. All conveniently in one place. And the full book is an awesome read too (IMHO the best out there for understanding how to really work with R).

Specify arity using only or except when importing function on Elixir

I'm studying Elixir and when I use only or except operators when importing functions from a module I need to specify an arity number. Why?
e.g.
import :math, only: [sqrt: 1]
or
import :math, except: [sin: 1, cos: 1]
Across the Erlang ecosystem functions are identified by name + arity. In most other languages you can overload functions by name. In other words, in the Erlang world foo/1 (that is, foo(one_arg)) is a completely different function than foo/2 (as in, foo(one_arg, two_arg)), but in Python or Ruby "foo" is the complete function identity and it can be invoked with a flexible number of arguments.
The convention is to name functions that mean the same thing the same name, especially in the case of recursively defined iterative functions like:
factorial(N) -> factorial(1, N).
factorial(A, 0) -> A;
factorial(A, N) -> factorial(A * N, N - 1).
Notice there are two periods, meaning there are two completely independent definitions here. We could just as well write:
fac(N) -> sum(1, N).
sum(A, 0) -> A;
sum(A, N) -> sum(A * N, N - 1).
But you will notice that the second version's savings in terms of character strokes is drastically outweighed by the convolution of its semantics -- the second version's internal function name is an outright lie!
The convention is to name related functions the same thing, but in actuality overloading functions by arity is not allowed in the Erlang ecosystem. To make such overloading acceptable would require significant feature additions to the compiler of a language that compiles to Erlang's bytecode, and that would be a pointless waste of painful effort. The current situation is about as good as we can get in a dynamically typed functional language (without it becoming a statically typed functional language... and that's another discussion entirely).
The end result is that you have to specify exactly what function you want to import, whether in Erlang or Elixir, and that means identifying it by name + arity. Recognizing that the common convention is to use the same name for functions that do the same thing but have different argument counts (often simply writing a cascade of curried definitions to enclose common defaults), Elixir provides a shortcut to including functions by groups instead of enumerating them.
So when you import :math, only: [sqrt: 1] you only take math:sqrt/1 and left the rest of the module out (were there a math:sqrt/2 you would have ignored it). When you import :math, except: [sin: 1, cos: 1] you take everything but math:sin/1 and math:cos/1 (were there a math:sin/2 you would have taken it). The name + arity is a distinct identity. Imagine a big KV store of available functions. The keys are {module, func, arity}, meaning they are an atomic value to the system. If you're familiar with Erlang even a little this may strike you as familiar, because you deal with the tuple {Module, Function, Args} all the time.
Functions in Erlang and Elixir are uniquely identified by module/name/arity. In order to import/exclude the correct function, you need to specify all three parts. Another way of understanding this is to consider the case of capturing function references, e.g. &Map.get/2.
Even if two functions share the same name, they are actually completely different functions to the VM. In order to reference the correct one, you have to correctly identify the function you wish to call, hence the need to specify all three components with only, except.

Resources