With FP you can always code in functional style ...Style - yes. But it would be just mimic or bad parody.
I am trying to understand the buzz about "functional programming". It sounds like using functions without modifying parameters, and no global side effects. This sounds old school to me. Anyone care to elucidate?
I am trying to understand the buzz about "functional programming". It sounds like using functions without modifying parameters, and no global side effects. This sounds old school to me. Anyone care to elucidate?
You are right. Indeed Lisp was born in 1958!
Nothing new here ;)
I am trying to understand the buzz about "functional programming". It sounds like using functions without modifying parameters, and no global side effects. This sounds old school to me. Anyone care to elucidate?Partially it can be viewed that way, but functional programming can be viewed in a wider way. The go to language for functional programming, Haskell, is one of very few that implements functional programming as pure as possible.
In truth, it is a revival, not a novelty, given that the functional one is the first invented paradigm.
I would like to have the first class functions in FreePascal, in particular the possibility of using anonymous functions and closures.
I guess anonymous functions are another significant piece of it though. Apparently in Delphi, but not in Free Pascal yet?
I would like to have the first class functions in FreePascal, in particular the possibility of using anonymous functions and closures.Speaking of stateless way of development.
Well, there is always some buzz.
If you want some good background on the paradigm, then maybe this will help: https://www.youtube.com/watch?v=sqV3pL5x8PI
[But when using an anonymous function / closure... creating a test seems to be problematic, because the entire function body needs to be copied over to the test itself.
You have the same problems with nested functions today already. Essentially there is no good way to test them.I would like to have the first class functions in FreePascal, in particular the possibility of using anonymous functions and closures.Speaking of stateless way of development.
Could one explain on how to test an anonymous function and/or closure?
I'm talking about computer science, not automatic calculation or programmable mechanical machines. I refer to the Lambda calculus of Alonzo Church, which precedes the Turing machine.
So what you mean to say is that the term "functional programming" was coined by computer science at its inception to describe what Lisp does. I quite simply don't buy it as a description of the real world.
(Slightly later) Sorry, I've just seen your
> However, leaving theoretical issues for a while, Fortran (imperative) was born in 1954, where Lisp (functional) in 1958. Thus, from this point of view, you are right :)
I'd also say that I'm not /completely/ hostile to this sort of thing, and I've seen some quite interesting work which used Lisp as a low-level stepping stone to something that more closely resembled what today we'd call a "real" language. But I've studied the history of early programming languages sufficiently to be able to see exactly "where McCarthy was coming from" and what he was trying to do, and while I don't deny that some interesting work has come out of the Lisp camp it was, basically a dead-end approach: in much the same way that intersting concepts came out of Modula-2 while the language itself was a dead end.
Well, there is always some buzz.The video explains quite well what functional programming is, but the Java example is horrific. Beside I don't understand why people use Java or other C-style languages to explain algorithms, you should use a language you know. But even fixing the bugs, the implementation of the SUM function is wrong in 3 or more ways.
If you want some good background on the paradigm, then maybe this will help: https://www.youtube.com/watch?v=sqV3pL5x8PI
Function Sum(inputs:array of integer):Integer; Var V:Integer; Begin Result:=0; For V in inputs do Result+=V; End; procedure TForm1.Button1Click(Sender: TObject); begin Caption := Sum([1,2,3,4,5]).ToString; end;
Nothing new here ;)
I think it can be done better (I mean, more functional):
FUNCTION Sum (CONST Values: ARRAY OF INTEGER): INTEGER; BEGIN IF Length (Values) = 1 THEN RESULT := LOW (Values) ELSE RESULT := Sum (Slice (Values, Length (Values) - 1) + HIGH (Values) END;
In spite of the appearance, we probably have similar ideas. Although the 'basically a dead-end approach' statement about Lisp seems too severe to me.
I think it can be done better (I mean, more functional):
FUNCTION Sum (CONST Values: ARRAY OF INTEGER): INTEGER; BEGIN IF Length (Values) = 1 THEN RESULT := LOW (Values) ELSE RESULT := Sum (Slice (Values, Length (Values) - 1) + HIGH (Values) END;
[side note] I think the RTL needs the SliceR function, same than Slice but using the right side.
And what will return SumL([])?
function SumL(const Values: array of Integer): Integer; begin if Length(Values) = 1 then SumL := Values[Low(Values)] else SumL := SumL(Values[0..High(Values) - 1]) + Values[High(Values)]; end; ...
But all this is purely theoretical entertainment, since the FPC is not able to optimize tail recursion, right?
Have you succeeded to make it work?If you have problem with tail recursion optimization give code example please.
And what will return SumL([])?
function SumL(const Values: array of Integer): Integer; begin if Length(Values) = 1 then SumL := Values[Low(Values)] else SumL := SumL(Values[0..High(Values) - 1]) + Values[High(Values)]; end; ...
As for me it's betterBut all this is purely theoretical entertainment, since the FPC is not able to optimize tail recursion, right?
function SumL(const Values: array of Integer): Integer; begin if Length(Values) = 0 then exit(0); SumL := SumL(Values[0..High(Values) - 1]) + Values[High(Values)]; end;
The way I see it, there are five fundamental notations: ALGOL, APL, Forth, Lisp and Smalltalk. Of those, only ALGOL (hence Pascal, C and the rest) "do the expected thing" when presented with the algebraic notation taught to schoolchildren for the last couple of hundred years, and I think it says a lot that when there were competing suggestions for Ada- at a time when Lisp et al. had a substantially higher profile than today- all of the proposals were ALGOL-based despite that not- as far as I'm aware- being a precondition.
The way I see it, there are five fundamental notations: ALGOL, APL, Forth, Lisp and Smalltalk. Of those, only ALGOL (hence Pascal, C and the rest) "do the expected thing" when presented with the algebraic notation taught to schoolchildren for the last couple of hundred years, and I think it says a lot that when there were competing suggestions for Ada- at a time when Lisp et al. had a substantially higher profile than today- all of the proposals were ALGOL-based despite that not- as far as I'm aware- being a precondition.
Where does Fortran fit into your scheme? If Turbo Pascal had not been developed, I'd likely still be using Fortran.
@PascalDragon, thanks a lot.
Indeed, I tested with the const parameter:Now with the var parameter it works on Win64 compiler. Does this seem to be somehow documented?
function SumL(const Values: array of Integer): Integer; function Sum(const a: array of Integer; v0: Integer): Integer; begin if Length(a) = 0 then exit(v0); Sum := Sum(a[0..High(a) - 1], v0 + a[High(a)]); end; begin Result := Sum(Values, 0); end;
However, the Win32 compiler persistently generates recursive code:
P$TAIL_REC$_$SUML$array_of_LONGINT$$LONGINT_$$_SUM$array_of_LONGINT$LONGINT$$LONGINT: ; [10] begin push ebp mov ebp,esp lea esp,dword ptr [esp-4] push ebx push esi ; Var $parentfp located at ebp-4, size=OS_32 ; Var $result located in register ebx mov dword ptr [ebp-4],eax ; Var a located in register edx ; Var $highA located in register ecx mov eax,dword ptr [ebp+8] ; Var v0 located in register eax ; [11] if Length(a) = 0 then exit(v0); lea ebx,dword ptr [ecx+1] test ebx,ebx jne @@j8 mov ebx,eax jmp @@j5 @@j8: ; Peephole Optimization: MovLea2Add done ; [12] Sum := Sum(a[0..High(a) - 1], v0 + a[High(a)]); add eax,dword ptr [edx+ecx*4] push eax ; Peephole Optimization: Lea2Sub done sub ecx,1 mov eax,dword ptr [ebp-4] call P$TAIL_REC$_$SUML$array_of_LONGINT$$LONGINT_$$_SUM$array_of_LONGINT$LONGINT$$LONGINT mov ebx,eax @@j5: ; [13] end; mov eax,ebx pop esi pop ebx mov esp,ebp pop ebp ret 4 _CODE ENDS
@LeledumboWhich one? Lazy evaluation is somewhat tied to functional programming, but not all functional programming languages implement it. Meanwhile, it's possible to implement it in imperative language, but will not look as natural as in functional language. e.g.: this is a function returning infinite list of fibonacci numbers:
That does require quite a different mindset than I am used to. Is that more about Haskell, or functional programming in general?
I just watched a short video on lambda calculus, the way they presented a function, a black box with input and output, is how I normally try to write a function.Yes, as how it's defined in math. The blackbox, however, is not a series of command or steps to produce output based on input, but an expression, just like in math. And expression is the core of functional programming. As I've shown previously, not all functions will be compiled into functions in assembly. They can be eliminated completely or simplified as far as possible even into a simple value assignment only (if the function call can be executed at compile time).
I guess anonymous functions are another significant piece of it though. Apparently in Delphi, but not in Free Pascal yet?WIP and partially working in trunk, AFAIK. Or is it still in separate branch?
The later.I guess anonymous functions are another significant piece of it though. Apparently in Delphi, but not in Free Pascal yet?WIP and partially working in trunk, AFAIK. Or is it still in separate branch?
No, as these things change/improve with each version. E.g. yesterday Florian helped me to work out how to get constant and by-value open array parameters working as well, so that will probably soon be in trunk (and maybe 3.2) as well. ;)Good news.
That appears to be a bug detecting the tail call correctly. Would you please report it?Just tested SumL against i386-win32 rev.44002 - works as expected. :D
Updated my version as well. :-[ It indeed works correctly now. :)That appears to be a bug detecting the tail call correctly. Would you please report it?Just tested SumL against i386-win32 rev.44002 - works as expected. :D
Implemented in r44012 (https://svn.freepascal.org/cgi-bin/viewvc.cgi?view=revision&revision=44012). :)No, as these things change/improve with each version. E.g. yesterday Florian helped me to work out how to get constant and by-value open array parameters working as well, so that will probably soon be in trunk (and maybe 3.2) as well. ;)Good news.
You have two errors in there: you need to use Values[LOW(Values)] and Values[HIGH(Values)].Doh! %) I've fixed it. Maybe I'm not the genius I though. :-[
Behold the slice operator (it's documented here (https://www.freepascal.org/docs-html/current/ref/refsu68.html#x180-20200014.4.5) at the bottom):Thanks for the tip. Didn't know it was possible. I wonder if Delphi supports that too.
function SumR(const Values: array of Integer): Integer; begin if Length(Values) = 1 then SumR := Values[Low(Values)] else SumR := SumR(Values[1..High(Values)]) + Values[Low(Values)]; end;