Hacker News new | ask | show | jobs
by charlysl 2784 days ago
According to the pdf's author, the crucial feature of FP is that there is no visible non-determinism. This means that every time you call a function with the same arguments it is guaranteed that you will get the same result. The other key feature is that there are no visible side-effects when calling a function.

Tail recursion of course is great to have, but you can certainly FP without it, even in a language that supports it. I mean, what if you don't put the recursive call in tail position in a function written in a language that supports tail recursion? It would still be FP.

2 comments

The no non-determinism feature is very good example why TCO/TCE is crucial - each time you call a recursive function the state is changing- another stack is created. Therefore the same function which operates on unknown argument size(list, tree) can have different behavior - stack overflow might happen or not and we don’t know when.
You can get that in Java as well.

Just create a static class without member fields where the class plays the role of a poor man's ML module, with all static functions only interacting with their parameters.

Then static import it into the client package.

This is not the way to do FP in Java though. Even before lambdas were introduced, you could do FP in Java. This is actually the whole point of GoF design patterns such as Interpreter and Visitor, which together with Composite are the way to write recursive data definitions (and functions that operate on them) in Java (or C++). The whole idea of "Little Languages" is FP, representing operations as data, as an AST.

How to do FP in Java is very well explained in the MIT OCW course 6.005 "Elements of Software Construction", 2008 [1], in particular in lectures 10, 11, 13, 14 & 15.

Remember that you can create closures with inner classes.

As for the fact that in Java you could have state inside, say, a Visitor, the program can still be FP, if you know what you are doing. The point is that when doing FP in a language like Java, you are adopting a definitional approach to FP, which is totally legit: any operation is FP if it is deterministic and has no visible side-effects (a corollary is that then it wouldn't have any observable state of its own, it would be reactive). This is sort of a "if it walks like a duck ..." approach to FP.

In fact, this is exactly what is going on when you are doing reactive programming in a non FP language like Javascript, where there are no restrictions to doing destructive assignment anywhere. This doesn't stop you from doing reactive programming, as long as you follow certain guidelines (because the language won't stop you from infringing them and having state).

How is this possible? The reason is that the OO computation model subsumes FP: anything you can express in an FP language, you can express in an OO language, and then some (although not as naturally, there is more plumbing in the way).

The reverse is not true, and this is a good thing, it is exactly what allows FP to have all those desirable properties.

[1] https://ocw.mit.edu/courses/electrical-engineering-and-compu...

Sounds good in theory but is never going to work in practice. Even static functions can store state and access global singletons, disk or the internet. Java doesn't have a way to specify constness of arguments either so preventing mutating an argument is very difficult.

Is time and memory usage a side effect btw? :)