Форум по программированию Delphi Sources

 



Вернуться   Форум по программированию Delphi Sources > Все о Delphi > Синтаксис
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 22.08.2017, 13:44
shonty shonty вне форума
Прохожий
 
Регистрация: 22.08.2017
Сообщения: 2
Версия Delphi: lazarus
Репутация: 10
По умолчанию Функция из переменной

Подскажите пожалуйста, как вызвать функцию из переменной?

Задача такая:
Имеется пять функций (одностроковых например: f4:=500*1.2*1000/(Rvar/100*x+R880)) и процедура (многострочная), строящая график на канве.

Можно конечно и пять процедур накопипастить, под каждую функцию... Но..

Не могу понять, как в процедуру ввести переменную (например F) и согласно условию подставлять в неё какую-либо из фцнкций (тиапа F:=f1, F:=f2, и т.д.).
Ответить с цитированием
  #2  
Старый 22.08.2017, 13:54
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59585
По умолчанию

Указатель на функцию. Как это делается при динамическом вызове dll.
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
Этот пользователь сказал Спасибо NumLock за это полезное сообщение:
shonty (23.08.2017)
  #3  
Старый 23.08.2017, 06:14
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 7,519
Версия Delphi: 7, XE3, 10.2
Репутация: 49088
По умолчанию

Дополню немного.
Есть 2 типа функций. Просто функции и методы класса.
Для первого варианта можно так:
Код:
type
  TFunc = function (x : double) : double;

function f1(x : double) : double;
begin
  result := x+1; // просто для примера
end;

function f2(x : double) : double;
begin
  result := x-1;
end;

function CalcFunc(x1, x2, dx : double; func : TFunc) : double;
var
  i : double;
begin
  // просто бред для примера
  result := 0;
  i := x1;
  while i <= x2 do
    begin
      result := result + func(i);
      i := i + dx;
    end;
end;

// где-то вызов
begin
  writeln('f1 ->', CalcFunc(1,5,0.2,f1);
  writeln('f2 ->', CalcFunc(1,5,0.2,f2);
end;

Для второго случая есть 2 подварианта.

а. Тоже самое, только тип описан как
Код:
type
  TFunc = function (x : double) : double of object;
тогда в основную функцию можно передавать методы любого класса.

б. Передавать объект класса. тогда их можно "нанаследовать" от одного родителя. Там есть еще вариант с мета классом.
Код:
unit Unit2;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TFuncClass = class
    class function Name : String; virtual;
    class function f(x : double) : double; virtual;
  end;

  TMetaClass = class of TFuncClass;

  TF1 = class(TFuncClass)
    class function Name : String; override;
    class function f(x : double) : double; override;
  end;

  TF2 = class(TFuncClass)
    class function Name : String; override;
    class function f(x : double) : double; override;
  end;

  TForm2 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    function Calc(x1, x2, dx : double; cls : TMetaClass) : double;
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

class function TFuncClass.Name : String;
begin
  result := 'TFuncClass';
end;

class function TFuncClass.f(x : double) : double;
begin
  Raise Exception.Create('Should not be called.');
end;

class function TF1.Name : String;
begin
  result := 'f1';
end;

class function TF1.f(x : double) : double;
begin
  result := x + 1;
end;

class function TF2.Name : String;
begin
  result := 'f2';
end;

class function TF2.f(x : double) : double;
begin
  result := x - 1;
end;

function TForm2.Calc(x1, x2, dx : double; cls : TMetaClass) : double;
var
  i : double;
begin
  result := 0;
  i := x1;
  while i <= x2 do
    begin
      result := result + cls.f(i);
      i := i + dx;
    end;
end;

procedure TForm2.Button1Click(Sender: TObject);
begin
  Memo1.Lines.Add(Format('class %s, name %s -> %.4f',[TF1.ClassName,TF1.Name,Calc(1,5,0.2,TF1)]));
  Memo1.Lines.Add(Format('class %s, name %s -> %.4f',[TF2.ClassName,TF2.Name,Calc(1,5,0.2,TF2)]));
end;

end.
В результате нажатия на кнопку в Memo имеем:
Код:
class TF1, name f1 -> 78,0000
class TF2, name f2 -> 38,0000
Обрати внимание на тип TMetaClass.

ЗЫ. Я там совместил вызов собственно функции, форматирование строки и ее добавление в Memo. Думаю, разберешся.

ЗЗЫ. Для особо умных. Мне просто было интересно - помню ли я как работать с метаклассами, последний раз делал такое лет 8 назад. Что-то еще помню, написал с первого раза без ошибок.

Последний раз редактировалось lmikle, 23.08.2017 в 06:17.
Ответить с цитированием
Этот пользователь сказал Спасибо lmikle за это полезное сообщение:
shonty (23.08.2017)
  #4  
Старый 23.08.2017, 09:34
shonty shonty вне форума
Прохожий
 
Регистрация: 22.08.2017
Сообщения: 2
Версия Delphi: lazarus
Репутация: 10
По умолчанию

Цитата:
Сообщение от lmikle
Дополню немного.
Совсем чуть-чуть
Цитата:
Сообщение от lmikle
...Есть 2 типа функций. Просто функции и методы класса.
Для первого варианта можно так:
Да, спасибо, выбрал первый вариант, разобрался, работает.

PS
Мне, как простому советскому радиолюбителю, для подбора резисторов в регуляторе тока (а зависимости сильно нелинейны) нужна программа для отображения графиков.
А хотел выкрутится так:
var a, b, c, d, e;
F:=a*(fnc1)+b*(fnc2)+c*(fnc3)+d*(fnc4)+e*(fnc5)
и подстановкой переменных a,b,c,d,e в "0" и "1" выбирать нужный участок выражения
Теперь сделаю как положено
Ответить с цитированием
  #5  
Старый 23.08.2017, 21:38
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 7,519
Версия Delphi: 7, XE3, 10.2
Репутация: 49088
По умолчанию

Если пишешь для себя, то сойдет. Если собираешься делиться, то еще приделай возможность грузиить эти функции из dll, тогда можно будет расширять набор функций не меняя основную программу. Код не намного сложнее получится. Только надо будет сделать получение адресов таких же функций из dll'ей и сохранение их в спике для дальнейшего вызова.
Ну и , насколько я помню, там еще куча интересных зависимостей есть, фильтров от емкостей и индуктивностей, например).
Ответить с цитированием
  #6  
Старый 25.08.2017, 08:46
Аватар для M.A.D.M.A.N.
M.A.D.M.A.N. M.A.D.M.A.N. вне форума
Sir Richard Abramson
 
Регистрация: 05.04.2008
Сообщения: 5,503
Версия Delphi: XE10
Репутация: выкл
По умолчанию

Эх, эмбаркадера им лямбды с дженериками дала — используй лямбды с дженериками, используй — не хочу.
Код:
function demo(f1, f2: TFunc<integer, Integer>): integer;
begin
  result := f1(f2(1)); // compose functions
end;

...

foo := demo(
  function (a: integer): integer
  begin
    result := a+1;
  end,
  function (a: integer): integer
  begin
    result := a-1;
  end)

...
использование лямбд из переменных

f1 =   function (a: integer): integer
  begin
    result := a+1;
  end;

f2 =   function (a: integer): integer
  begin
    result := a-1;
  end;

bar = demo(f1, f2)
__________________
— Как тебя понимать?
— Понимать меня не обязательно. Обязательно меня любить и кормить вовремя.


На Delphi, увы, больше не программирую.
Рекомендуемая литература по программированию

Последний раз редактировалось M.A.D.M.A.N., 25.08.2017 в 08:49.
Ответить с цитированием
Этот пользователь сказал Спасибо M.A.D.M.A.N. за это полезное сообщение:
shonty (25.08.2017)
  #7  
Старый 25.08.2017, 22:27
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 7,519
Версия Delphi: 7, XE3, 10.2
Репутация: 49088
По умолчанию

Угу, Мэд. С какой версии лямбда доступна?
А дженерики тут явно будут менее удобны, бо как разница как раз не в типах данных, а в самой формуле.
Так что классическое решение с указателем на функцию в данном конкретном случае самое оптимальное. Как я уже писал, даже тот код, через мета класс, это явный overkill и просто был написан что бы вспомнить самому как с ними работать.
Ответить с цитированием
  #8  
Старый 26.08.2017, 17:56
Аватар для M.A.D.M.A.N.
M.A.D.M.A.N. M.A.D.M.A.N. вне форума
Sir Richard Abramson
 
Регистрация: 05.04.2008
Сообщения: 5,503
Версия Delphi: XE10
Репутация: выкл
По умолчанию

Цитата:
Сообщение от lmikle
Угу, Мэд. С какой версии лямбда доступна?
А дженерики тут явно будут менее удобны, бо как разница как раз не в типах данных, а в самой формуле.
Так что классическое решение с указателем на функцию в данном конкретном случае самое оптимальное. Как я уже писал, даже тот код, через мета класс, это явный overkill и просто был написан что бы вспомнить самому как с ними работать.
С 2009 дельфи.

Дженерики для динамической типизации, в примере они лишние, но ТСу будет полезно знать про них.

Почему я против указателей: использование анонимных методов делает код по структуре более логичным и более гибким (композиция функций, каррирование, замыкания), в виде некоего лаконичного решения, тебе как программисту не надо перетыркиватсья в кучу мест и смотреть где что объявлено и как (а еще перегрузка функций — злое зло). Использование указателей — это какое-то получистемное программирование получается, программист вместо того, чтоб решать проблему задачи — решает проблему языка программирования/компилятора, в этом нет ничего плохого, если будешь во всей этой херне ориентироваться и понимать что там и про что.

Резюмируя вышеописанное: если инструмент программирования предоставляет инструментарий для решения задачи лаконично и понятно (и, уж тем более, быстро — время-деньги), то решать задачу используя устаревшие и/или достаточно сложные инструментарии я считаю моветоном.

В общем, тут дело хозяйское, решайте задачу как хотите, целью моего поста было показать, что задачу можно решить несколько более элегантно и лаконично.
__________________
— Как тебя понимать?
— Понимать меня не обязательно. Обязательно меня любить и кормить вовремя.


На Delphi, увы, больше не программирую.
Рекомендуемая литература по программированию
Ответить с цитированием
Этот пользователь сказал Спасибо M.A.D.M.A.N. за это полезное сообщение:
shonty (27.08.2017)
  #9  
Старый 26.08.2017, 20:25
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 7,519
Версия Delphi: 7, XE3, 10.2
Репутация: 49088
По умолчанию

Цитата:
Сообщение от GOOGLE
Lambdas are just a different form of anonymous methods, which were introduced in Delphi 2009, with a very minimal syntax that makes them cryptic and hard to read. (No function header to speak of, for example, which means that you can't tell the type of the variables you're working with by looking at the code.)Jan 4, 2011
Ну а дженерики, как уже было сказано, тут явно лишние.
А указатель на функцию можно потом использовать для имплементации расширений в виде плагинов, собственно, только надо будет дописать загрузку функций из библиотек.
Так что я бы сам в реальной задаче остановился бы, скорее всего, на первом способе, т.к. достаточно простой, при правильной струкрутизации кода проблем с поддержкой нет, и расширяемый в будущем.
Ответить с цитированием
Ответ



Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 05:13.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources", 2004-2019

ВКонтакте   Facebook   Twitter