Table of Contents

Procedural Type

Procedural Type คืออะไร

คือ การสร้างตัวแปรชนิดที่เป็น procedure/function เพื่อให้สามารถนำไปใส่ใน input Argument ของ procedure/function อันอื่นได้ หรือเรียกอีกอย่างหนึ่งคือ การทำให้ procedure/function กลายเป็นตัวแปร

รูปแบบ

Procedural Type มีรูปแบบดังนี้

Topic Format
Type Declaration
TYPE
  TFunc1 = function(x:integer):real; //for function 1-argument
  TFunc2 = function(x,y:integer):real; //for function 2-arguments
  
  TProc = procedure; //for procedure with no argument
  TProc1 = procedure(y:string); //for procedure 1-argument

Example-1: Function Finding Max Value

Example-1: Function Finding Max Value

ตัวอย่าง การส่ง function เข้าไปอีก function หนึ่ง
ข้อสังเกต: การหาค่าสูงสุดของ function โดยการสร้าง function ที่มีชื่อว่า Find_Max จะสังเกตว่าภายใน function ดังกล่าว มีการเรียก function จากภายนอกเข้ามาคำนวณ ซึ่งเรียกว่า f() ดังนั้นเราจึงต้องกำหนดให้ f() เป็นตัวแปรชนิด Procedural Type
สำหรับ Lazarus การเรียก func เข้ามาใน Find_Max ในบรรทัดที่ 30 จะเป็นการเรียกผ่าน Pointer ดังนั้นจึงต้องใส่ @ นำหน้าชื่อ function เสมอ

PROGRAM Find_MaxValue_Of_Function;

TYPE
  Tfunc = function(x:real):real; //Procedural Type

//define polynomial function f(x) = x^2+2*x-5
//This function has the Max value = 15 at x = 5
function func(x:real):real;
begin
  result:=-x*x+10*x-10 ;  
end;

function Find_Max(f:Tfunc; xFirst,xLast,increment:real):real;
var x,xMax,max:real;
begin
  x:=xFirst;
  xMax:=x;
  max:= f(x);
  while x<xLast do
   begin
     x:=x+increment;
     if f(x)>max then xMax := x;
     max:= f(x);
   end;
  result:=f(xMax);
end;

//Call the above function
BEGIN
  writeln('Max value between x = 0 to x = 10 is : ',Find_Max(@func,0,10,0.001));
  readln;
END.  


ข้อแตกต่างระหว่าง Lazaus กับ Delphi

ข้อสังเกต การใส่ function เข้าไปสำหรับ lazarus กับ delphi จะแตกต่างกัน โดย Lazarus จะใช้การส่งค่าผ่าน pointer ดังนั้นจึงต้องมีเครื่องหมาย @ นำหน้าชื่อ function แต่สำหรับ delphi สามารถส่งชื่อ function เข้าไปได้เลย ดูตัวอย่างที่ 2

Example-2: Function Finding Max Value (Delphi)

Example-2: Function Finding Max Value (Delphi)

PROGRAM Find_MaxValue_Of_Function;

{$MODE delphi}

TYPE
  Tfunc = function(x:real):real; //Procedural Type

//define polynomial function f(x) = x^2+2*x-5
//This function has the Max value = 15 at x = 5
function func(x:real):real;
begin
  result:=-x*x+10*x-10 ;  
end;

function Find_Max(f:Tfunc; xFirst,xLast,increment:real):real;
var x,xMax,max:real;
begin
  x:=xFirst;
  xMax:=x;
  max:= f(x);
  while x<xLast do
   begin
     x:=x+increment;
     if f(x)>max then xMax := x;
     max:= f(x);
   end;
  result:=f(xMax);
end;

//Call the above function
BEGIN
  writeln('Max value between x = 0 to x = 10 is : ',Find_Max(func,0,10,0.001));
  readln;
END.


Function of Object

ตัวอย่างข้างบนนั้น ใช้ได้กับกรณีที่ function ถูกประกาศเป็น Global Scope เท่านั้น (จะสังเกตว่า func ไม่ได้อยู่ภายใต้ Class หรือ Object ใดๆ) ในกรณีที่ function ถูกประกาศเป็น Local Scope ภายใต้ Class หรือ Object ใดๆ จะต้องเปลี่ยนการประกาศ Type ใหม่เป็นดังนี้

Type 
  TFunc = function(x:real):real of Object ;

Example-3: Function of Object (TForm)

Example-3: Function of Object (TForm)

ตัวอย่าง การประกาศ Procedural Type ของ function ที่ประกาศภายใต้ Form1
ข้อสังเกต: การประกาศจะต้องมีคำว่า of object ต่อท้ายเสมอ

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs;

type

  Tfunc = function(x:real):real of object; //Procedural Type

  { TForm1 }

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private

  public
    function func(x:real):real;
  end;

var
  Form1: TForm1;
  function Find_Max(f:Tfunc; xFirst,xLast,increment:real):real;

implementation

function Find_Max(f: Tfunc; xFirst, xLast, increment: real): real;
var x,xMax,max:real;
begin
  x:=xFirst;
  xMax:=x;
  max:= f(x);
  while x<xLast do
   begin
     x:=x+increment;
     if f(x)>max then xMax := x;
     max:= f(x);
   end;
  result:=f(xMax);
end;

{$R *.lfm}

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
  showmessage('Max value between x = 0 to x = 10 is : ' + 
  FloatToStr(Find_Max(@func,0,10,0.001)));
end;

function TForm1.func(x: real): real;
begin
  result:=-x*x+10*x-10 ;
end;

end.
  


Function is Nested

สำหรับการทำ Nested Function ให้กลายเป็น Procedural Type เพื่อส่งผ่านเป็นตัวแปรนั้น เราสามารถระบุ Function ดังกล่าวได้ตามนี้

Type 
  TFunc = function(x:real):real is Nested ;

จะสังเกตได้ว่าคล้ายกับการระบุ Function of Object นั่นเอง เพียงแต่เปลี่ยนจากคำว่า of Object เป็น is Nested แต่อย่างไรก็ตามสิ่งที่แตกต่างกันอีกอย่างหนึ่ง คือ คำสั่งข้างต้น จำเป็นต้องระบุ Compiler Directive ดังนี้ก่อนเสมอ

{$modeswitch nestedprocvars}