Recent

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

SymbolicFrank

  • Hero Member
  • *****
  • Posts: 635
Re: Functional programming in Pascal
« Reply #45 on: June 30, 2019, 12:22:03 pm »
Btw.

This is not a lambda function. It's seems you still don't get the conceptual idea behind lambdas/anonymous functions.

To you, this is a lambda function:

Code: [Select]
LAMBDA::=lambda [(LAMBDABPARAMS)] as EXPR
LAMBDAPARAMS::=LAMBDAPARAM[;LAMBDAPARAMS]
LAMBDAPARAM::=IDENTLIST[:TYPE]
IDENTLIST::=IDENTIFIER[,IDENTIFIER]

and this an anonymous function:

Behind the scenes it's an interface with only an Invoke() method that's implemented by a class instance. This class instance is shared by all anonymous functions of a single scope. Though this is all an implementation detail.

although the latter possibly also could include a function without a name that is executed immediately. That's already three different definitions for the same concept. Closures are often (at least for Thaddy) seen as something different as well.

To me, it's all different implementations of the same thing: an unnamed block of calculations that is applied to some data that is in scope. I would include enumerators (for..in) here as well. And it's all a variant of the Pascal nested function, often with a different syntax.

In short:

1. Definitions can be implementation-specific, but shouldn't be.
2. Implementing the same thing multiple times with a different syntax as copied from a different language doesn't automatically make it a new or important addition to the language, or allow new functionality.
3. The reason why nested functions in Pascal have a name is simply so you can define them in a correct way. It is the same reason there are no inline variable definitions.

PascalDragon

  • Hero Member
  • *****
  • Posts: 674
  • Compiler Developer
Re: Functional programming in Pascal
« Reply #46 on: June 30, 2019, 05:17:47 pm »
The Invoke() is an implementation detail. Anonymous functions have the following syntax:

Code: [Select]
ANONFUNC::=FUNCHEADER|PROCHEADER BLOCK
FUNCHEADER::=function[(PARAMLIST)]:TYPE DIRECTIVES
PROCHEADER::=procedure[(PARAMLIST)]:TYPE DIRECTIVES
PARAMLIST::=PARAMDECL[;PARAMLIST]
PARAMDECL::=PARAMIDENTLIST:TYPE
PARAMIDENTLIST::=[var|const|out|constref|] IDENTIFIERLIST
IDENTIFIERLIST::=IDENTIFIER[,IDENTIFIERLIST]

As you can see with a quick example (I'll use the one from above) this is a rather verbose syntax:

Code: Pascal  [Select]
  1. var
  2.   l: TList<TPerson>;
  3. begin
  4.   l.Sort(
  5.     function(aLeft, aRight: TPerson): Boolean
  6.     begin
  7.       Result := aLeft.Age < aRight.Age;
  8.     end
  9.   );
  10. end.

The idea of the lambda syntax to have an alternative, more compact syntax that is still clear for the developer:

Code: Pascal  [Select]
  1. var
  2.   l: TList<TPerson>;
  3. begin
  4.   l.Sort(
  5.     lambda (aLeft, aRight) as aLeft.Age < aRight.Age
  6.  );
  7. end.

Behind the scenes both use the same "reference to X" mechanism that uses a compiler generated interface with a Invoke method.

And enumerators are definitely not part of this. They are types that have a MoveNext method and a Current property that fits to the types of a for x in a statement.

Coroutines will hopefully be able to be mapped to the same mechanism as anonymous functions (or at least the same mechanisms with extensions). But first anonymous functions must finally be finished.

By the way: the syntax for anonymous functions with function and procedure is non negotiatable as that syntax is needed for Delphi compatibility.

lucamar

  • Hero Member
  • *****
  • Posts: 2086
Re: Functional programming in Pascal
« Reply #47 on: June 30, 2019, 07:10:04 pm »
By the way: the syntax for anonymous functions with function and procedure is non negotiatable as that syntax is needed for Delphi compatibility.

Thank the gods! It may be that I'm actually getting old and becoming fixed-minded but I find that sintax actually ... reassuring. No mistery there, just plain old clothes even if doned in a somewhat new way :D
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.2/2.0.4  - FPC 3.0.4 on:
(K|L)Ubuntu 12..16, Windows XP SP3, various DOSes.

Zoran

  • Hero Member
  • *****
  • Posts: 1465
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: Functional programming in Pascal
« Reply #48 on: July 01, 2019, 10:29:59 am »
In this lambda syntax the parameter types and the result type are not declared explicitely? :o
Only now I noticed that. May I hope it will never get into our language.

PascalDragon

  • Hero Member
  • *****
  • Posts: 674
  • Compiler Developer
Re: Functional programming in Pascal
« Reply #49 on: July 02, 2019, 09:23:37 am »
In this lambda syntax the parameter types and the result type are not declared explicitely? :o
Only now I noticed that. May I hope it will never get into our language.
Yes, that would require type inference. That's why I said that I'm still sceptical about adding this syntax at all. On the other hand it allows for a much more compact syntax, especially for simple lambda expressions (just compare the two examples I've given).

jamie

  • Hero Member
  • *****
  • Posts: 2101
Re: Functional programming in Pascal
« Reply #50 on: July 03, 2019, 02:24:57 am »
I wrote a complete script parser language using Variants.

 A single function could return any type the variant could handle.

 Also, many of the input variables were also variants..
 
 Kind of a twisted way of doing things but it got me through..
Number 1 at blue screen app creations!

440bx

  • Hero Member
  • *****
  • Posts: 1205
Re: Functional programming in Pascal
« Reply #51 on: July 03, 2019, 03:22:07 am »
In this lambda syntax the parameter types and the result type are not declared explicitely? :o
Only now I noticed that. May I hope it will never get into our language.
Yes, that would require type inference. That's why I said that I'm still sceptical about adding this syntax at all. On the other hand it allows for a much more compact syntax, especially for simple lambda expressions (just compare the two examples I've given).

Just curious... couldn't the example you gave be implemented without having to use type inference ... something along the lines of ...
Code: Pascal  [Select]
  1. var
  2.   l: TList<TPerson>;
  3. begin
  4.   l.Sort(
  5.      lambda (aLeft, aright : TPerson) : boolean as aLeft.Age < aRight.Age
  6.   );
  7. end.
  8.  
It isn't as concise as the construct you showed but, it seems to be more in tune with the Pascal way.


using FPC v3.0.4 and Lazarus 1.8.2 on Windows 7 64bit.

Zoran

  • Hero Member
  • *****
  • Posts: 1465
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: Functional programming in Pascal
« Reply #52 on: July 03, 2019, 10:00:29 am »

Just curious... couldn't the example you gave be implemented without having to use type inference ... something along the lines of ...
Code: Pascal  [Select]
  1. var
  2.   l: TList<TPerson>;
  3. begin
  4.   l.Sort(
  5.      lambda (aLeft, aright : TPerson) : boolean as aLeft.Age < aRight.Age
  6.   );
  7. end.
  8.  
It isn't as concise as the construct you showed but, it seems to be more in tune with the Pascal way.

Then, what is the problem with:
Code: Pascal  [Select]
  1. var
  2.   l: TList<TPerson>;
  3. begin
  4.   l.Sort(
  5.      function(aLeft, aright: TPerson): Boolean; begin Result := aLeft.Age < aRight.Age end
  6.   );
  7. end.
  8.  
:)
« Last Edit: July 03, 2019, 10:12:34 am by Zoran »

Thaddy

  • Hero Member
  • *****
  • Posts: 9194
Re: Functional programming in Pascal
« Reply #53 on: July 03, 2019, 10:09:22 am »
@Zoran

nail on head...  :) :) :) :)

Note similar is already possible with function pointers. In that sense it is syntactic sugar anyway.
« Last Edit: July 03, 2019, 10:22:32 am by Thaddy »
also related to equus asinus.

440bx

  • Hero Member
  • *****
  • Posts: 1205
Re: Functional programming in Pascal
« Reply #54 on: July 03, 2019, 01:27:20 pm »
Then, what is the problem with:
Code: Pascal  [Select]
  1. var
  2.   l: TList<TPerson>;
  3. begin
  4.   l.Sort(
  5.      function(aLeft, aright: TPerson): Boolean; begin Result := aLeft.Age < aRight.Age end
  6.   );
  7. end.
  8.  
:)
I don't see a problem with it. I think it is perfectly fine.

The lambdas do result in very short constructs but part of how they achieve it is using type inference.  The short and succinct syntax is nice, as long as it doesn't come from minuses such as type inference.   What I showed was something that seemed to strike a balance.


@Thaddy,

I agree, it is mostly syntactic sugar.  I say mostly because, after all, it is a construct that preserves the linearity of the execution flow (something I greatly value.)  A function pointer doesn't achieve that.  With a function pointer, you have to jump somewhere in the code to read whatever function the pointer is referencing.


using FPC v3.0.4 and Lazarus 1.8.2 on Windows 7 64bit.

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 7510
Re: Functional programming in Pascal
« Reply #55 on: July 03, 2019, 01:36:29 pm »
(before overuse of anonymous methods, specially for threading, also check this thread:

https://forum.lazarus.freepascal.org/index.php/topic,45832.30.html)
« Last Edit: July 03, 2019, 03:12:37 pm by marcov »

PascalDragon

  • Hero Member
  • *****
  • Posts: 674
  • Compiler Developer
Re: Functional programming in Pascal
« Reply #56 on: July 03, 2019, 01:41:43 pm »

Just curious... couldn't the example you gave be implemented without having to use type inference ... something along the lines of ...
Code: Pascal  [Select]
  1. var
  2.   l: TList<TPerson>;
  3. begin
  4.   l.Sort(
  5.      lambda (aLeft, aright : TPerson) : boolean as aLeft.Age < aRight.Age
  6.   );
  7. end.
  8.  
It isn't as concise as the construct you showed but, it seems to be more in tune with the Pascal way.

Then, what is the problem with:
Code: Pascal  [Select]
  1. var
  2.   l: TList<TPerson>;
  3. begin
  4.   l.Sort(
  5.      function(aLeft, aright: TPerson): Boolean; begin Result := aLeft.Age < aRight.Age end
  6.   );
  7. end.
  8.  
:)
Yes, that's the problem if one does not use type inference: Then there is basically no real difference to the syntax that Delphi has.
Note similar is already possible with function pointers. In that sense it is syntactic sugar anyway.
For that specific example this is true. However with anonymous functions you can also have state attached to the "function pointer" and pass the pointer plus the state (together a "function reference") to some outer scope.

440bx

  • Hero Member
  • *****
  • Posts: 1205
Re: Functional programming in Pascal
« Reply #57 on: July 03, 2019, 01:50:23 pm »
(before overuse of anonymous methods, specially for threading, also check this thread:

https://forum.lazarus.freepascal.org/index.php/topic,45927.msg325474.html#msg325474 )
Marco, that thread has nothing to do with anonymous methods and/or threading.
using FPC v3.0.4 and Lazarus 1.8.2 on Windows 7 64bit.

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 7510
Re: Functional programming in Pascal
« Reply #58 on: July 03, 2019, 03:13:14 pm »
(before overuse of anonymous methods, specially for threading, also check this thread:

https://forum.lazarus.freepascal.org/index.php/topic,45927.msg325474.html#msg325474 )
Marco, that thread has nothing to do with anonymous methods and/or threading.

Fixed, thanks for the hint. Probably copied the wrong one.

Zoran

  • Hero Member
  • *****
  • Posts: 1465
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: Functional programming in Pascal
« Reply #59 on: July 03, 2019, 03:15:55 pm »
Note similar is already possible with function pointers. In that sense it is syntactic sugar anyway.
For that specific example this is true. However with anonymous functions you can also have state attached to the "function pointer" and pass the pointer plus the state (together a "function reference") to some outer scope.

Yes, and state is the new feature that anonymous functions bring. For trivial things, I would rather avoid these, they would just make code less readable.

We will be able to do something like this:
Code: Pascal  [Select]
  1. type
  2.   TDivideByNumerFunction: function(N: Integer): Integer is reference;
  3.  
  4. function CreateDivideByNumberFunction(D: Integer): TDivideByNumberFunction;
  5. begin
  6. // D has to be remembered by the resulting function, so that is its "state", right?
  7.   Result := function (N: Integer): Integer; begin Result := N div D end;
  8. // Result := lambda (N) as N div D; // alternative syntax with type inherence.
  9. end;
  10.  
  11. var
  12.   DivideByTwo, DivideByThree: TDivideByNumberFunction;
  13.  
  14. begin
  15.   DivideByTwo := CreateDivideByNumberFunction(2);
  16.   DivideByThree := CreateDivideByNumberFunction(3);
  17.  
  18. // Now, we have two functions actually, as if we had declared these:
  19. // function DivideByTwo(N: Integer): Integer; begin Result := N div 2 end;
  20. // function DivideByThree(N: Integer): Integer; begin Result := N div 3 end;
  21.  
  22.   Writeln(DivideByTwo(12)); // the output is 6
  23.   Writeln(DivideByThree(12)); // 4
  24.   Writeln(DivideByTwo(17)); // 8
  25.   Writeln(DivideByThree(21)); // 7
  26.  
  27.   Readln;
  28. end.
  29.  

That is some kind of partial specialization. Without generics.

I hope I understood this feature, please correct me if not.