Recursion of internal functions in Erlang - recursion

Playing with Erlang, I've got a process-looping function like:
process_loop(...A long list of parameters here...) ->
receive
...Message processing logic involving the function parameters...
end,
process_loop(...Same long list of parameters...)
end.
It looks quite ugly, so I tried a refactoring like that:
process_loop(...A long list of parameters...) ->
Loop = fun() ->
receive
...Message processing logic...
end,
Loop()
end,
Loop()
end.
But it turned out to be incorrect, as Loop variable is unbound inside the Loop function. So, I've arranged a workaround:
process_loop(...A long list of parameters...) ->
Loop = fun(Next) ->
receive
...Message processing logic...
end,
Next(Next)
end,
Loop(Loop)
end.
I have two questions:
Is there a way to achieve the idea of snippet #2, but without such "Next(Next)" workarounds?
Do snippets #1 and #3 differ significantly in terms of performance, or they're equivalent?

No. Unfortunately anonymous function are just that. Anonymous, unless you give them a name.
Snippet #3 is a little bit more expensive. Given that you do pattern matching on messages in the body, I wouldn't worry about it. Optimise for readability in this case. The difference is a very small constant factor.

You might use tuples/records as named parameters instead of passing lots of parameters. You can just reuse the single parameter that the function is going to take.
I guess (but I' not sure) that this syntax isn't supported by proper tail-recursion. If you refactor to use a single parameter I think that you will be again on the right track.

The more conventional way of avoiding repeating the list of parameters in snippet #1 is to put all or most of them in a record that holds the loop state. Then you only have one or a few variables to pass around in the loop. That's easier to read and harder to screw up than playing around with recursive funs.

I must say that in all cases where I do this type of recursion I don't think I have ever come across the case where exactly the same set of variables is passed around in the recursion. Usually variables will change reflecting state change in the process loop. It cannot be otherwise as you have to handle state explicitly. I usually group related parameters into records which cuts down the number of arguments and adds clarity.
You can of course use your solution and have some parameters implicit in the fun and some explicit in the recursive calls but I don't think this would improve clarity.
The same answer applies to "normal" recursion where you are stepping over data structures.

Related

Julia functions: making mutable types immutable

Coming from Wolfram Mathematica, I like the idea that whenever I pass a variable to a function I am effectively creating a copy of that variable. On the other hand, I am learning that in Julia there are the notions of mutable and immutable types, with the former passed by reference and the latter passed by value. Can somebody explain me the advantage of such a distinction? why arrays are passed by reference? Naively I see this as a bad aspect, since it creates side effects and ruins the possibility to write purely functional code. Where I am wrong in my reasoning? is there a way to make immutable an array, such that when it is passed to a function it is effectively passed by value?
here an example of code
#x is an in INT and so is immutable: it is passed by value
x = 10
function change_value(x)
x = 17
end
change_value(x)
println(x)
#arrays are mutable: they are passed by reference
arr = [1, 2, 3]
function change_array!(A)
A[1] = 20
end
change_array!(arr)
println(arr)
which indeed modifies the array arr
There is a fair bit to respond to here.
First, Julia does not pass-by-reference or pass-by-value. Rather it employs a paradigm known as pass-by-sharing. Quoting the docs:
Function arguments themselves act as new variable bindings (new
locations that can refer to values), but the values they refer to are
identical to the passed values.
Second, you appear to be asking why Julia does not copy arrays when passing them into functions. This is a simple one to answer: Performance. Julia is a performance oriented language. Making a copy every time you pass an array into a function is bad for performance. Every copy operation takes time.
This has some interesting side-effects. For example, you'll notice that a lot of the mature Julia packages (as well as the Base code) consists of many short functions. This code structure is a direct consequence of near-zero overhead to function calls. Languages like Mathematica and MatLab on the other hand tend towards long functions. I have no desire to start a flame war here, so I'll merely state that personally I prefer the Julia style of many short functions.
Third, you are wondering about the potential negative implications of pass-by-sharing. In theory you are correct that this can result in problems when users are unsure whether a function will modify its inputs. There were long discussions about this in the early days of the language, and based on your question, you appear to have worked out that the convention is that functions that modify their arguments have a trailing ! in the function name. Interestingly, this standard is not compulsory so yes, it is in theory possible to end up with a wild-west type scenario where users live in a constant state of uncertainty. In practice this has never been a problem (to my knowledge). The convention of using ! is enforced in Base Julia, and in fact I have never encountered a package that does not adhere to this convention. In summary, yes, it is possible to run into issues when pass-by-sharing, but in practice it has never been a problem, and the performance benefits far outweigh the cost.
Fourth (and finally), you ask whether there is a way to make an array immutable. First things first, I would strongly recommend against hacks to attempt to make native arrays immutable. For example, you could attempt to disable the setindex! function for arrays... but please don't do this. It will break so many things.
As was mentioned in the comments on the question, you could use StaticArrays. However, as Simeon notes in the comments on this answer, there are performance penalties for using static arrays for really big datasets. More than 100 elements and you can run into compilation issues. The main benefit of static arrays really is the optimizations that can be implemented for smaller static arrays.
Another package-based options suggested by phipsgabler in the comments below is FunctionalCollections. This appears to do what you want, although it looks to be only sporadically maintained. Of course, that isn't always a bad thing.
A simpler approach is just to copy arrays in your own code whenever you want to implement pass-by-value. For example:
f!(copy(x))
Just be sure you understand the difference between copy and deepcopy, and when you may need to use the latter. If you're only working with arrays of numbers, you'll never need the latter, and in fact using it will probably drastically slow down your code.
If you wanted to do a bit of work then you could also build your own array type in the spirit of static arrays, but without all the bells and whistles that static arrays entails. For example:
struct MyImmutableArray{T,N}
x::Array{T,N}
end
Base.getindex(y::MyImmutableArray, inds...) = getindex(y.x, inds...)
and similarly you could add any other functions you wanted to this type, while excluding functions like setindex!.

Why are while loops predicated on typechecking (w/ tc_expr) the condition expression?

It seems that tc_expr is constrained to knowledge of the typing context and nothing else so it is not possible to safely "typecheck" an expression that requires knowledge of the heap state, e.g. a pointer dereference as the condition of a while loop. Why is that and would it ever be possible for me to prove correct a loop such as:
char *t = ...;
...
while (*t != 0)
{
...
t++;
}
I would think while loops could optionally be proven with a variation of tc_expr that does allow for pointer dereference by accounting for the heap context along with the typing context. I suspect that the thinking is that a loop condition should be a “pure” expression, but I’m ultimately curious if that is really a necessary constraint.
P.S. I realize that I could rewrite this as a for loop. My question still stands knowing that VST allows me to prove this kind of loop albeit with different syntax.
Answer number 1: It's a design decision, one way or the other, and we found that many things are simpler (and more in the spirit of Separation Logic) if expressions do not access memory.
Answer number 2: You can write this while loop, just as it is. Then use clightgen with the -normalize flag (which you should always use anyway), and then you can verify it. However, in such a case, the loop form will not be (strictly speaking) a Clight "while" loop, it will have it's loop-test (if (?) then /*skip*/; else break;) in the middle of the loop body; so you will use forward_loop to prove it, instead of forward_while.

What is the mechanism behind Function Application in Functional Programming

OK, let me try to rephrase my question.
Actually I wanted to know how is Function Application implemented in FP.
Is it done like a function call in imperative languages, where a stack frame is added for each call and removed on each return.
Or, is it like in inline functions, where the function call statement is replaced by the function definition.
Also, in terms of implementation of a function application, what is the significance of the statement functions in FP are mappings between domains and corresponding ranges. It is obviously not possible to maintain a mapping for each domain-range entry pair, so what exactly does the statement imply...
This question is broad enough that I can't answer it completely, since I don't know every single functional programming language. But I can tell you how it's done in one language, F#. You asked whether function application is done like a function call in imperative languages (another stack frame added for each call) or whether it's done as inline functions... and in F# the answer is both. The F# compiler is allowed to choose whether to create a stack-frame-using function call, or whether to inline the function at the call site; generally the choice is made based on the size of the compiled function. If the function compiles down to fewer than N bytes of compiled code (I can't tell you the exact number, but knowing the exact number doesn't actually matter) then the compiler will usually inline that function call; if it takes more than N bytes then the function call will use a stack frame. (Except in the case of tail-recursive calls, which are compiled to the equivalent of a goto and don't use a stack frame).
P.S. You can force the compiler's hand by using the inline keyword, which forces that function to be inlined at the call site every time. Most F# programmers don't recommend doing that on a regular basis, because the compiler is smart enough that it's usually not a good idea to override its decisions. (Also, the inline keyword means that the types of the function's parameters must be resolvable at compile time, so there are some functions for which that changes the semantics, but that's a little off-topic for the question you asked so I won't go into it. Except to say that in F#, statically-resolved type parameters or SRTPs are a very complicated subject, and you can do some very advanced things with them if you understand them.)

Is recursion a feature in and of itself?

...or is it just a practice?
I'm asking this because of an argument with my professor: I lost credit for calling a function recursively on the basis that we did not cover recursion in class, and my argument is that we learned it implicitly by learning return and methods.
I'm asking here because I suspect someone has a definitive answer.
For example, what is the difference between the following two methods:
public static void a() {
return a();
}
public static void b() {
return a();
}
Other than "a continues forever" (in the actual program it is used correctly to prompt a user again when provided with invalid input), is there any fundamental difference between a and b? To an un-optimized compiler, how are they handled differently?
Ultimately it comes down to whether by learning to return a() from b that we therefor also learned to return a() from a. Did we?
To answer your specific question: No, from the standpoint of learning a language, recursion isn't a feature. If your professor really docked you marks for using a "feature" he hadn't taught yet, that was wrong.
Reading between the lines, one possibility is that by using recursion, you avoided ever using a feature that was supposed to be a learning outcome for his course. For example, maybe you didn't use iteration at all, or maybe you only used for loops instead of using both for and while. It's common that an assignment aims to test your ability to do certain things, and if you avoid doing them, your professor simply can't grant you the marks set aside for that feature. However, if that really was the cause of your lost marks, the professor should take this as a learning experience of his or her own- if demonstrating certain learning outcomes is one of the criteria for an assignment, that should be clearly explained to the students.
Having said that, I agree with most of the other comments and answers that iteration is a better choice than recursion here. There are a couple of reasons, and while other people have touched on them to some extent, I'm not sure they've fully explained the thought behind them.
Stack Overflows
The more obvious one is that you risk getting a stack overflow error. Realistically, the method you wrote is very unlikely to actually lead to one, since a user would have to give incorrect input many many times to actually trigger a stack overflow.
However, one thing to keep in mind is that not just the method itself, but other methods higher or lower in the call chain will be on the stack. Because of this, casually gobbling up available stack space is a pretty impolite thing for any method to do. Nobody wants to have to constantly worry about free stack space whenever they write code because of the risk that other code might have needlessly used a lot of it up.
This is part of a more general principle in software design called abstraction. Essentially, when you call DoThing(), all you should need to care about is that Thing is done. You shouldn't have to worry about the implementation details of how it's done. But greedy use of the stack breaks this principle, because every bit of code has to worry about how much stack it can safely assume it has left to it by code elsewhere in the call chain.
Readability
The other reason is readability. The ideal that code should aspire to is to be a human-readable document, where each line describes simply what it's doing. Take these two approaches:
private int getInput() {
int input;
do {
input = promptForInput();
} while (!inputIsValid(input))
return input;
}
versus
private int getInput() {
int input = promptForInput();
if(inputIsValid(input)) {
return input;
}
return getInput();
}
Yes, these both work, and yes they're both pretty easy to understand. But how might the two approaches be described in English? I think it'd be something like:
I will prompt for input until the input is valid, and then return it
versus
I will prompt for input, then if the input is valid I will return it, otherwise I get the input and return the result of that instead
Perhaps you can think of slightly less clunky wording for the latter, but I think you'll always find that the first one is going to be a more accurate description, conceptually, of what you are actually trying to do. This isn't to say recursion is always less readable. For situations where it shines, like tree traversal, you could do the same kind of side by side analysis between recursion and another approach and you'd almost certainly find recursion gives code which is more clearly self-describing, line by line.
In isolation, both of these are small points. It's very unlikely this would ever really lead to a stack overflow, and the gain in readability is minor. But any program is going to be a collection of many of these small decisions, so even if in isolation they don't matter much, it's important to learn the principles behind getting them right.
To answer the literal question, rather than the meta-question: recursion is a feature, in the sense that not all compilers and/or languages necessarily permit it. In practice, it is expected of all (ordinary) modern compilers - and certainly all Java compilers! - but it is not universally true.
As a contrived example of why recursion might not be supported, consider a compiler that stores the return address for a function in a static location; this might be the case, for example, for a compiler for a microprocessor that does not have a stack.
For such a compiler, when you call a function like this
a();
it is implemented as
move the address of label 1 to variable return_from_a
jump to label function_a
label 1
and the definition of a(),
function a()
{
var1 = 5;
return;
}
is implemented as
label function_a
move 5 to variable var1
jump to the address stored in variable return_from_a
Hopefully the problem when you try to call a() recursively in such a compiler is obvious; the compiler no longer knows how to return from the outer call, because the return address has been overwritten.
For the compiler I actually used (late 70s or early 80s, I think) with no support for recursion the problem was slightly more subtle than that: the return address would be stored on the stack, just like in modern compilers, but local variables weren't. (Theoretically this should mean that recursion was possible for functions with no non-static local variables, but I don't remember whether the compiler explicitly supported that or not. It may have needed implicit local variables for some reason.)
Looking forwards, I can imagine specialized scenarios - heavily parallel systems, perhaps - where not having to provide a stack for every thread could be advantageous, and where therefore recursion is only permitted if the compiler can refactor it into a loop. (Of course the primitive compilers I discuss above were not capable of complicated tasks like refactoring code.)
The teacher wants to know whether you have studied or not. Apparently you didn't solve the problem the way he taught you (the good way; iteration), and thus, considers that you didn't. I'm all for creative solutions but in this case I have to agree with your teacher for a different reason: If the user provides invalid input too many times (i.e. by keeping enter pressed), you'll have a stack overflow exception and your solution will crash. In addition, the iterative solution is more efficient and easier to maintain. I think that's the reason your teacher should have given you.
Deducting points because "we didn't cover recursion in class" is awful. If you learnt how to call function A which calls function B which calls function C which returns back to B which returns back to A which returns back to the caller, and the teacher didn't tell you explicitly that these must be different functions (which would be the case in old FORTRAN versions, for example), there is no reason that A, B and C cannot all be the same function.
On the other hand, we'd have to see the actual code to decide whether in your particular case using recursion is really the right thing to do. There are not many details, but it does sound wrong.
There are many point of views to look at regarding the specific question you asked but what I can say is that from the standpoint of learning a language, recursion isn't a feature on its own. If your professor really docked you marks for using a "feature" he hadn't taught yet, that was wrong but like I said, there are other point of views to consider here which actually make the professor being right when deducting points.
From what I can deduce from your question, using a recursive function to ask for input in case of input failure is not a good practice since every recursive functions' call gets pushed on to the stack. Since this recursion is driven by user input it is possible to have an infinite recursive function and thus resulting in a StackOverflow.
There is no difference between these 2 examples you mentioned in your question in the sense of what they do (but do differ in other ways)- In both cases, a return address and all method info is being loaded to the stack. In a recursion case, the return address is simply the line right after the method calling (of course its not exactly what you see in the code itself, but rather in the code the compiler created). In Java, C, and Python, recursion is fairly expensive compared to iteration (in general) because it requires the allocation of a new stack frame. Not to mention you can get a stack overflow exception if the input is not valid too many times.
I believe the professor deducted points since recursion is considered a subject of its own and its unlikely that someone with no programming experience would think of recursion. (Of course it doesn't mean they won't, but it's unlikely).
IMHO, I think the professor is right by deducting you the points. You could have easily taken the validation part to a different method and use it like this:
public bool foo()
{
validInput = GetInput();
while(!validInput)
{
MessageBox.Show("Wrong Input, please try again!");
validInput = GetInput();
}
return hasWon(x, y, piece);
}
If what you did can indeed be solved in that manner then what you did was a bad practice and should be avoided.
Maybe your professor hasn't taught it yet, but it sounds like you're ready to learn the advantages and disadvantages of recursion.
The main advantage of recursion is that recursive algorithms are often much easier and quicker to write.
The main disadvantage of recursion is that recursive algorithms can cause stack overflows, since each level of recursion requires an additional stack frame to be added to the stack.
For production code, where scaling can result in many more levels of recursion in production than in the programmer's unit tests, the disadvantage usually outweighs the advantage, and recursive code is often avoided when practical.
Regarding the specific question, is recursion a feature, I'm inclined to say yes, but after re-interpreting the question. There are common design choices of languages and compilers that make recursion possible, and Turing-complete languages do exist that don't allow recursion at all. In other words, recursion is an ability that is enabled by certain choices in language/compiler design.
Supporting first-class functions makes recursion possible under very minimal assumptions; see writing loops in Unlambda for an example, or this obtuse Python expression containing no self-references, loops or assignments:
>>> map((lambda x: lambda f: x(lambda g: f(lambda v: g(g)(v))))(
... lambda c: c(c))(lambda R: lambda n: 1 if n < 2 else n * R(n - 1)),
... xrange(10))
[1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880]
Languages/compilers that use late binding, or that define forward declarations, make recursion possible. For example, while Python allows the below code, that's a design choice (late binding), not a requirement for a Turing-complete system. Mutually recursive functions often depend on support for forward declarations.
factorial = lambda n: 1 if n < 2 else n * factorial(n-1)
Statically typed languages that allow recursively defined types contribute to enabling recursion. See this implementation of the Y Combinator in Go. Without recursively-defined types, it would still be possible to use recursion in Go, but I believe the Y combinator specifically would be impossible.
From what I can deduce from your question, using a recursive function to ask for input in case of input failure is not a good practice. Why?
Because every recursive functions call gets pushed on to the stack. Since this recursion is driven by user input it is possible to have an infinite recursive function and thus resulting in a StackOverflow :-p
Having a non recursive loop to do this is the way to go.
Recursion is a programming concept, a feature (like iteration), and a practice. As you can see from the link, there's a large domain of research dedicated to the subject. Perhaps we don't need to go that deep in the topic to understand these points.
Recursion as a feature
In plain terms, Java supports it implicitly, because it allows a method (which is basically a special function) to have "knowledge" of itself and of others methods composing the class it belongs to. Consider a language where this is not the case: you would be able to write the body of that method a, but you wouldn't be able to include a call to a within it. The only solution would be to use iteration to obtain the same result. In such a language, you would have to make a distinction between functions aware of their own existence (by using a specific syntax token), and those who don't! Actually, a whole group of languages do make that distinction (see the Lisp and ML families for instance). Interestingly, Perl does even allow anonymous functions (so called lambdas) to call themselves recursively (again, with a dedicated syntax).
no recursion?
For languages which don't even support the possibility of recursion, there is often another solution, in the form of the Fixed-point combinator, but it still requires the language to support functions as so called first class objects (i.e. objects which may be manipulated within the language itself).
Recursion as a practice
Having that feature available in a language doesn't necessary mean that it is idiomatic. In Java 8, lambda expressions have been included, so it might become easier to adopt a functional approach to programming. However, there are practical considerations:
the syntax is still not very recursion friendly
compilers may not be able to detect that practice and optimize it
The bottom line
Luckily (or more accurately, for ease of use), Java does let methods be aware of themselves by default, and thus support recursion, so this isn't really a practical problem, but it still remain a theoretical one, and I suppose that your teacher wanted to address it specifically. Besides, in the light of the recent evolution of the language, it might turn into something important in the future.

if and elsif optimisation in Ada 95

I'm working on an Ada based project that I'm not terribly familiar with, and I've just seen something that at first glance seems inefficient, but of course that all depends on what the compiler might do.
if Ada.Strings.Fixed.Trim
(Source => Test_String,
Side => Ada.Strings.Both) =
String_1 then
--Do something here
elsif Ada.Strings.Fixed.Trim
(Source => Test_String,
Side => Ada.Strings.Both) =
String_2 then
--Do something else here
end if;
I feel that it would be more efficient to call the Trim procedure and store the result in a String variable, then test against different Strings in each condition of the if statement, especially if there are many conditions to check (never mind that using a binary search might be even better). Of course, I may be wrong, so my question is, is there something about compile time optimisation in Ada that I do not know about, that might cause the Trim function to only be called once, and only have the result tested in each condition of the if statement?
That would be compiler-dependent, not language-dependent. Certainly, GNAT GPL 2013 calls Trim twice both at -O2 and at -O3.
Your (and my) intuition seems to be right: do the trim once and store the result ...
Trimmed : constant String :=
Ada.Strings.Fixed.Trim (Source => Test_String, Side => Ada.Strings.Both);
... though personally I’d write
Trimmed : constant String :=
Ada.Strings.Fixed.Trim (Test_String, Side => Ada.Strings.Both);
on the grounds that in this case no one should need the named parameter association to clarify the programmer’s intention!
I don't think we need to worry about efficiency for this case. But the coding style that do need to be improved. To define a variable to hold the result of the Trim function is a better practice in my opinion. The program logic is clearer and easier for maintenance.
Let's say you want to change the Trim function to another one or change the parameter passing in, you only need to change one place. Although for this case there are only two places, you still have a chance to error. If there are more cases to test, then there definitely will be missing case.
While I have no disagreement whatsoever with your assessment or Simon's answer, it's worth bearing in mind what optimisation actually means...
If each call to "trim" takes (conservatively) 0.1ms of CPU time, and the rewrite takes 2 minutes, the breakeven point in time saved is over 1 million executions of that particular statement!
This of course ignores (a) on the positive side, the value of gaining experience, and (b) on the negative side, the fact that CPU time is nowadays less valuable than your time. And (c) the time we have spent discussing the optimisation too!
With respect to "compile time optimisation in Ada" , the Ada language doesn't say anything about this. All it would say here is that the program must behave as if the function were called twice, i.e. it must produce the same results. But if the compiler "knows" that the function would produce the exact same result the second time, it can generate code that calls it only once. It can't do this for a function call in general, because a function could include side effects or use global variables that whose values could have changed. In this case, since the effects of Ada.Strings.Fixed.Trim are defined by the language and since those effects do guarantee that the effects would be the same, a compiler could, in theory, mark this function as one for which a call with the exact same parameters could be optimized. (A function in a Pure package would definitely be one where a second call could be eliminated, but unfortunately Ada.Strings.Fixed isn't defined by the Ada language as being Pure.) To find out whether a compiler actually does this particular optimization, though, you'd have to try it and check the code. I believe that if Test_String is not marked as Volatile, then compilers are allowed to assume that its value will be the same for each Ada.Strings.Fixed.Trim call (i.e. it can't be changed by another task in between the calls), but I'm not 100% sure about this.
I'd declare a constant to hold the result (like Simon), but for me this is more out of a desire to avoid duplicated code than it is out of a concern for efficiency.

Resources