Recent

Author Topic: Functional programming in Pascal  (Read 7425 times)

rnfpc

  • Jr. Member
  • **
  • Posts: 91
Functional programming in Pascal
« on: June 22, 2019, 10:38:53 am »
Are there functional programming methods in Pascal such as map, filter, apply, reduce, fold, foldl and foldr function? I could not find them on searching the internet. Possibly Pascal is a purely imperative language.

If not, is it possible to create a map function so that one can sent a list/array to it with a function and it return a new list/array with sent function applied to each element of sent list:

Code: Pascal  [Select]
  1. outlist := map(sentfunction, sentlist);

where sentfunction is a function which takes only one item and returns a modified item.
« Last Edit: June 22, 2019, 08:40:04 pm by rnfpc »

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 7508
Re: Functional programming in Pascal
« Reply #1 on: June 22, 2019, 10:47:18 am »
Pascal is mixed imperative-OOP. Conceptually the same level as C++.

There are no such functions. If they rely on functional lazy evaluation there also would be no point.

rsz

  • New Member
  • *
  • Posts: 13
Re: Functional programming in Pascal
« Reply #2 on: June 22, 2019, 11:58:06 am »
I was also wondering about this. Does FreePascal support anonymous functions or alike? something like this?

Code: Pascal  [Select]
  1. x := MyFunction(procedure begin
  2.     // do stuff
  3.   end)

One could easily implement map, fold, etc. if functions are to become first class in FreePascal. This would also open the door for other interesting concepts, such as easy "async" execution of functions. e.g.:
Code: Pascal  [Select]
  1. context := ExecuteAsync(procedure begin
  2.     // do stuff in another thread
  3.   end);
  4. // do stuff
  5. context.Await;

I'm still pretty new to FreePascal, so maybe something as easy as this is already possible?

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 7508
Re: Functional programming in Pascal
« Reply #3 on: June 22, 2019, 12:12:28 pm »
I was also wondering about this. Does FreePascal support anonymous functions or alike? something like this?

Code: Pascal  [Select]
  1. x := MyFunction(procedure begin
  2.     // do stuff
  3.   end)

Being worked on by an external contributor.  Slow progress.

Quote
One could easily implement map, fold, etc. if functions are to become first class in FreePascal. This would also open the door for other interesting concepts, such as easy "async" execution of functions. e.g.:
Code: Pascal  [Select]
  1. context := ExecuteAsync(procedure begin
  2.     // do stuff in another thread
  3.   end);
  4. // do stuff
  5. context.Await;

I'm still pretty new to FreePascal, so maybe something as easy as this is already possible?

Not yet. Delphi has some such features, though there are caveats (capturing the state of the anonymous function doesn't always goes right afaik). I use it in Delphi, but try to avoid complex parametrisation.

But it remains a bit of a kludge since it is bolted on functionality, rather than being in the core of the language like with functional languages. Also compiletime typing might restrict you from emulating functional language interpreters.

Lot of work, low gains. Rather than thinking in copying over language functionality, better restate your problem as cleanly as possible, and find a better way.

julkas

  • Sr. Member
  • ****
  • Posts: 416
  • KISS principle / Lazarus 2.0.0 / FPC 3.0.4
Re: Functional programming in Pascal
« Reply #4 on: June 22, 2019, 03:17:46 pm »
Are there functional programming methods in Pascal such as map, filter, apply, fold, foldl and foldr function? I could not find them on searching the internet. Possibly Pascal is a purely imperative language.
I know great map, filter, reduce,.. from Python!
My opinion - you should first think about how to describe, implement your data structure, algorithm in Pascal language and not about language features. It's not easy. Each programming language has it's own spirit, philosophy, strength and weakness.
Regards.

P.S. You can write your own map, filter, reduce,..
« Last Edit: June 22, 2019, 03:30:23 pm by julkas »
procedure mulu64(a, b: QWORD; out clo, chi: QWORD); assembler;
asm
  mov rax, a
  mov rdx, b
  mul rdx
  mov [clo], rax
  mov [chi], rdx
end;

PascalDragon

  • Hero Member
  • *****
  • Posts: 674
  • Compiler Developer
Re: Functional programming in Pascal
« Reply #5 on: June 22, 2019, 05:42:21 pm »
I was also wondering about this. Does FreePascal support anonymous functions or alike? something like this?

Code: Pascal  [Select]
  1. x := MyFunction(procedure begin
  2.     // do stuff
  3.   end)

One could easily implement map, fold, etc. if functions are to become first class in FreePascal.
As marcov wrote this is not yet possible, but you can do something like this (needs FPC 3.2.0 or newer):
Code: Pascal  [Select]
  1. program tmaptest;
  2.  
  3. {$mode objfpc}
  4.  
  5. type
  6.   generic TMapFunc<T> = function(constref aElem: T): T;
  7.  
  8. generic function Map<T>(aMapFunc: specialize TMapFunc<T>; constref aArr: specialize TArray<T>): specialize TArray<T>;
  9. var
  10.   i: SizeInt;
  11. begin
  12.   Result := Nil;
  13.   SetLength(Result, Length(aArr));
  14.   for i := 0 to High(aArr) do
  15.     Result[i] := aMapFunc(aArr[i]);
  16. end;
  17.  
  18. function TimesTwo(constref aArg: LongInt): LongInt;
  19. begin
  20.   Result := aArg * 2;
  21. end;
  22.  
  23. var
  24.   arr: array of LongInt;
  25.   i: LongInt;
  26. begin
  27.   arr := specialize Map<LongInt>(@TimesTwo, [3, 5, 6, 8]);
  28.   for i in arr do
  29.     Writeln(i);
  30. end.

Something like this can also be done for the other functions. Maybe one could implement a unit for functional algorithms like this and switch them over to anonymous routines once they're integrated into trunk. *shrugs*

SymbolicFrank

  • Hero Member
  • *****
  • Posts: 635
Re: Functional programming in Pascal
« Reply #6 on: June 22, 2019, 07:38:48 pm »
What is the problem that anonymous functions solve? I don't get it.

lainz

  • Hero Member
  • *****
  • Posts: 3284
    • Lainz
Re: Functional programming in Pascal
« Reply #7 on: June 22, 2019, 07:57:07 pm »
What is the problem that anonymous functions solve? I don't get it.

I think it depends on context. In JavaScript for example you can combine an anonymous function with an arrow function to access scope variables.

Code: Javascript  [Select]
  1. var a = 10; // this is inside some other function, not a global variable
  2. myarr.filter(value=>{
  3.   return value == a; // can access "a" var
  4. })

the "value => {}" is an anonymous arrow function with a single parameter. You can do something like:

Code: Javascript  [Select]
  1. var a = 10; // this is inside some other function, not a global variable
  2. myarr.filter(function (value) {
  3.   return value == 10; // cant access "a" here
  4. })

But you can't access "a" inside that function.

With FPC the paradigm is OOP, so if you work with objects and classes, there is no need of sharing the scope, since is self contained in the class. In other words in a class you can always access "a" because it for example is declared in the private section, and the filter function is inside the class.

If you don't reuse the function, and is used in a single place, like filtering with a certain criteria a single time, why declaring a function in the namespace for it? That means that function is used only there and should not be used anywhere. That's is the thing I understand to use them.

If you think with functions it has sense. If you think with classes, maybe not, because you can always declare a private function that is not used outside. That doesn't happen in JavaScript (private doesn't exist as easy), for example where is allowed anonymous functions.
« Last Edit: June 22, 2019, 08:04:48 pm by Lainz »

SymbolicFrank

  • Hero Member
  • *****
  • Posts: 635
Re: Functional programming in Pascal
« Reply #8 on: June 22, 2019, 11:00:25 pm »
Something like this?

Code: Pascal  [Select]
  1. function IsNegative(SomeParam: Integer): Boolean;
  2. var
  3.   SomeVar: Integer;
  4.  
  5.   function Calculate: Boolean;
  6.   begin
  7.     Result := False;
  8.     if SomeVar < 0 then Result := True;
  9.   end;
  10.  
  11. begin
  12.   Result := Calculate;
  13. end;

They copies it from Pascal  ;)

lainz

  • Hero Member
  • *****
  • Posts: 3284
    • Lainz
Re: Functional programming in Pascal
« Reply #9 on: June 23, 2019, 12:50:48 am »
Exactly that, you get the same benefits and problems of doing that, specially knowing what exactly is in scope and what isn't.

jamie

  • Hero Member
  • *****
  • Posts: 2088
Re: Functional programming in Pascal
« Reply #10 on: June 23, 2019, 01:31:55 am »
Code: Pascal  [Select]
  1. type
  2.  
  3.   { TForm1 }
  4.  
  5.   TForm1 = class(TForm)
  6.     Button1: TButton;
  7.     procedure Button1Click(Sender: TObject);
  8.   private
  9.  
  10.   public
  11.  
  12.   end;
  13.  AFunction = Function(Sender:TList):TList;
  14. var
  15.   Form1: TForm1;
  16.  
  17. implementation
  18.  
  19. {$R *.lfm}
  20. Function Test(Sender:TList):TList;
  21. Begin
  22.   Result := Sender;
  23.   Beep;
  24. end;
  25.  
  26. Function Map(F:Afunction; AList:TList):TList;
  27. Begin
  28.   Result := F(Alist); //All functions must use same prototype..
  29. End;
  30.  
  31. { TForm1 }
  32.  
  33. procedure TForm1.Button1Click(Sender: TObject);
  34. Var
  35.   L:Tlist;
  36. begin
  37.   Map(@Test, L);
  38. end;
  39.  
  40. end.                                  
  41.  

This can only work if all functions past use the same prototype..
« Last Edit: June 23, 2019, 01:37:34 am by jamie »
Number 1 at blue screen app creations!

PascalDragon

  • Hero Member
  • *****
  • Posts: 674
  • Compiler Developer
Re: Functional programming in Pascal
« Reply #11 on: June 23, 2019, 11:54:38 am »
What is the problem that anonymous functions solve? I don't get it.
In this specific case they allow you to define the function "inline". My example from above (shortened), but with anonymous functions:
Code: Pascal  [Select]
  1. var
  2.   arr: array of LongInt;
  3.   i: LongInt;
  4. begin
  5.   arr := specialize Map<LongInt>(function(aElem: LongInt): LongInt begin Result := aElem * 2; end, [3, 5, 6, 8]);
  6.   for i in arr do
  7.     Writeln(i);
  8. end.
Due to the syntax of anonymous functions that looks a bit convoluted and once the functionality of anonymous functions is integrated into trunk I want to play around with a simpler syntax like this:
Code: Pascal  [Select]
  1. arr := specialize Map<LongInt>(lambda (aElem) as aElem * 2, [3, 5, 6, 8]);
This would require type inference for the lambda type and thus a new concept for Pascal so I'm a bit reluctant here, but I'll play around with it nevertheless.

And what anonymous functions allow as well is this:
Code: Pascal  [Select]
  1. var
  2.   arr: array of LongInt;
  3.   i, fac: LongInt;
  4. begin
  5.   fac := 42; // e.g. retrieved from some file or whatever
  6.   arr := specialize Map<LongInt>(function(aElem: LongInt): LongInt begin Result := aElem * fac; end, [3, 5, 6, 8]);
  7.   for i in arr do
  8.     Writeln(i);
  9. end.

The resulting anonymous function variable can also be passed outside of the scope it was declared in and still be used:
Code: Pascal  [Select]
  1. type
  2.   TMyFunc = function(aArg: LongInt): LongInt is reference;
  3.  
  4. function GetFunc(aArg: LongInt): TMyFunc;
  5. var
  6.   tmp: LongInt;
  7. begin
  8.   tmp := aArg * 2;
  9.   Result := function(aArg: LongInt): LongInt begin Result := aArg * tmp; end;
  10. end;
  11.  
  12. var
  13.   func: TMyFunc;
  14. begin
  15.   func := TMyFunc(2);
  16.   Writeln(func(4));
  17.   Writeln(func(6));
  18.   func := TMyFunc(4);
  19.   Writeln(func(4));
  20.   Writeln(func(6));
  21. end.
This is something that can't be replicated with nested functions outside of very simple cases.

rsz

  • New Member
  • *
  • Posts: 13
Re: Functional programming in Pascal
« Reply #12 on: June 23, 2019, 12:11:54 pm »
What is the problem that anonymous functions solve? I don't get it.
If you ever used a functional programming language like Haskell then you will miss them  ;D. They are especially useful for writing async or concise code that doesn't jump (spaghetti) all over the place, so it's easier to maintain. They are also very suited for one off functions, e.g. specific sort functions or a small block of code that you need often inside a single function but which doesn't deserve a place in the namespace because it is too specific.

Something like this?

Code: Pascal  [Select]
  1. function IsNegative(SomeParam: Integer): Boolean;
  2. var
  3.   SomeVar: Integer;
  4.  
  5.   function Calculate: Boolean;
  6.   begin
  7.     Result := False;
  8.     if SomeVar < 0 then Result := True;
  9.   end;
  10.  
  11. begin
  12.   Result := Calculate;
  13. end;

They copies it from Pascal  ;)
Very cool, I'll be using this until it lands. Do you know if the function gets inlined by fpc automatically, or do I have to declare it as inline?

Due to the syntax of anonymous functions that looks a bit convoluted and once the functionality of anonymous functions is integrated into trunk I want to play around with a simpler syntax like this:
Code: Pascal  [Select]
  1. arr := specialize Map<LongInt>(lambda (aElem) as aElem * 2, [3, 5, 6, 8]);
This would require type inference for the lambda type and thus a new concept for Pascal so I'm a bit reluctant here, but I'll play around with it nevertheless.
This would be nice if it's possible.

SymbolicFrank

  • Hero Member
  • *****
  • Posts: 635
Re: Functional programming in Pascal
« Reply #13 on: June 23, 2019, 12:58:00 pm »
PascalDragon, I do understand that you can make your code less readable by fitting everything on a single line. But is there any new functionality?

PascalDragon

  • Hero Member
  • *****
  • Posts: 674
  • Compiler Developer
Re: Functional programming in Pascal
« Reply #14 on: June 23, 2019, 02:36:57 pm »
Didn't you read what I wrote? It allows for functions together with state to be passed around outside of the scope they were declared in. Somewhat like nested functions, but not restricted to their point of declaration.