comp.lang.ada
 help / color / mirror / Atom feed
From: "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de>
Subject: Re: project euler 26
Date: Wed, 6 Sep 2023 09:06:31 +0200	[thread overview]
Message-ID: <ud98do$2dbqr$1@dont-email.me> (raw)
In-Reply-To: <87a5u0rts0.fsf@bsb.me.uk>

On 2023-09-06 03:10, Ben Bacarisse wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> 
>> On 2023-09-05 17:18, Ben Bacarisse wrote:
>>
>>> There was
>>> boiler plate code in my program that could be abstracted out into a
>>> generic function (or package?) so that any function can be maximised
>>> over some range or, better yet, any iterable type (if that's how Ada
>>> does things).
>>
>>> Can someone here show me how?
>>
>> You define some classes. Either generic or tagged. E.g. a generic class of
>> functions that uses two generic classes of the argument and the value:
>>
>> generic
>>     -- Ordered argument
>>     type Argument_Type is private;
>>     with function Next (Value : Argument_Type)
>>        return Argument_Type is <>;
>>     with function "<" (Left, Right : Argument_Type)
>>        return Boolean is <>;
>>     with function "=" (Left, Right : Argument_Type)
>>        return Boolean is <>;
>>     -- Comparable value
>>     type Value_Type is private;
>>     with function "<" (Left, Right : Value_Type ) return Boolean is <>;
>>     -- Function type
>>     with function Func (Argument : Argument_Type) return Value_Type;
>> function Generic_Maximum_At (Left, Right : Argument_Type)
>>     return Value_Type;
>>
>> and the implementation
>>
>> function Generic_Maximum_At (Left, Right : Argument_Type)
>>     return Value_Type is
>>     Argument : Argument_Type := Left;
>>     Max      : Value_Type;
>>     Value    : Value_Type;
>> begin
>>     if Right < Left then
>>        raise Constraint_Error with "Empty interval";
>>     end if;
>>     Max := Func (Argument);
>>     while not (Argument = Right) loop
>>        Argument := Next (Argument);
>>        Value := Func (Argument);
>>        if Max < Value then
>>           Max := Value;
>>        end if;
>>     end loop;
>>     return Max;
>> end Generic_Maximum_At;
>>
>> or you can choose to pass the function as an argument:
>>
>> generic
>>     -- Ordered argument
>>     type Argument_Type is private;
>>     with function Next (Value : Argument_Type)
>>        return Argument_Type is <>;
>>     with function "<" (Left, Right : Argument_Type)
>>        return Boolean is <>;
>>     -- Comparable value
>>     type Value_Type is private;
>>     with function "<" (Left, Right : Value_Type) return Boolean is <>;
>> function Generic_Maximum_At
>>           (  Left, Right : Argument_Type;
>>              Func : access function (Argument : Argument_Type)
>>                     return Value_Type
>>           )  return Value_Type;
>>
>> Or you can make it a package which is usually a better choice as one can
>> pack into it several entities sharing the same generic interface:
>>
>> generic
>>     -- Ordered argument
>>     type Argument_Type is private;
>>     with function Next (Value : Argument_Type)
>>        return Argument_Type is <>;
>>     with function "<" (Left, Right : Argument_Type )
>>        return Boolean is <>;
>>     with function "=" (Left, Right : Argument_Type)
>>        return Boolean is <>;
>>     -- Comparable value
>>     type Value_Type is private;
>>     with function "<" (Left, Right : Value_Type) return Boolean is <>;
>> package Generic_Discrete_Comparable_Valued is
>>     function Maximum_At
>>              (  Left, Right : Argument_Type;
>>                 Func : access function (Argument : Argument_Type)
>>                        return Value_Type
>>              )  return Value_Type;
>>     -- Other useless functions
>> end Generic_Discrete_Comparable_Valued;
>>
>> The generic classes of arguments/values can be in turn factored out into
>> reusable generic packages:
>>
>> generic
>>     -- Ordered argument
>>     type Argument_Type is private;
>>     with function Next (Value : Argument_Type) return Argument_Type is <>;
>>     with function "<" (Left, Right : Argument_Type) return Boolean is <>;
>>     with function "=" (Left, Right : Argument_Type) return Boolean is <>;
>> package Generic_Arguments is
>> end Generic_Arguments;
>>
>> generic
>>     -- Comparable value
>>     type Value_Type is private;
>>     with function "<" (Left, Right : Value_Type ) return Boolean is <>;
>> package Generic_Values is
>> end Generic_Values;
>>
>> generic
>>     with package Arguments is new Generic_Arguments (<>);
>>     with package Values is new Generic_Values (<>);
>> package Generic_Discrete_Comparable_Valued is
>>     use Arguments, Values;
>>     function Maximum_At
>>              (  Left, Right : Argument_Type;
>>                 Func : access function (Argument : Argument_Type)
>>                        return Value_Type
>>              )  return Value_Type;
>>     -- Other useless functions
>> end Generic_Discrete_Comparable_Valued;
> 
> Thank you.  I can't yet see how to use any of these alternatives, but
> that's my problem.

It is pretty much straightforward. E.g. the last one:

    package Arguments is new Generic_Arguments (Integer, Integer'Succ);
    package Values is new Generic_Values (Integer);
    package Functions is
       new Generic_Discrete_Comparable_Valued (Arguments, Values);

Now you can print the maximum of your Period function:

    Put_Line
    (  "Max at"
    &  Integer'Image (Functions.Maximum_At (2, 999, Period'Access))
    );

> Are there any good online sources on Ada generic
> programming so I can find out how to implement and use this short of
> package?

Actually I provided an implementation above. Here it is again:

package body Generic_Discrete_Comparable_Valued is
    function Maximum_At
             (  Left, Right : Argument_Type;
                Func : access function (Argument : Argument_Type)
                       return Value_Type
             )  return Value_Type is
       Argument : Argument_Type := Left;
       Max      : Value_Type;
       Value    : Value_Type;
    begin
       if Right < Left then
          raise Constraint_Error with "Empty interval";
       end if;
       Max := Func (Argument);
       while not (Argument = Right) loop
          Argument := Next (Argument);
          Value := Func (Argument);
          if Max < Value then
             Max := Value;
          end if;
       end loop;
       return Max;
    end Maximum_At;
end Generic_Discrete_Comparable_Valued;

(The packages Generic_Arguments and Generic_Values have no bodies)

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

  reply	other threads:[~2023-09-06  7:06 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-09-04  9:19 project euler 26 CSYH (QAQ)
2023-09-04 11:06 ` Niklas Holsti
2023-09-04 12:39   ` Dmitry A. Kazakov
2023-09-04 16:01     ` Ben Bacarisse
2023-09-04 19:20       ` Dmitry A. Kazakov
2023-09-04 20:18         ` Ben Bacarisse
2023-09-04 21:00           ` Dmitry A. Kazakov
2023-09-04 23:16             ` Ben Bacarisse
2023-09-05  7:23               ` Dmitry A. Kazakov
2023-09-05 15:18                 ` Ben Bacarisse
2023-09-05 17:08                   ` Dmitry A. Kazakov
2023-09-06  1:10                     ` Ben Bacarisse
2023-09-06  7:06                       ` Dmitry A. Kazakov [this message]
2023-09-06 15:16                         ` Ben Bacarisse
2023-09-06 15:54                           ` Dmitry A. Kazakov
2023-09-06 23:32                             ` Ben Bacarisse
2023-09-07  9:02                               ` Dmitry A. Kazakov
2023-09-08  1:32                                 ` Ben Bacarisse
2023-09-08  7:23                                   ` Dmitry A. Kazakov
2023-09-09  0:25                                     ` Ben Bacarisse
2023-09-09  9:32                                       ` Dmitry A. Kazakov
2023-09-10  1:20                                         ` Ben Bacarisse
2023-09-10  8:46                                           ` Dmitry A. Kazakov
2023-09-10 19:22                                             ` Ben Bacarisse
2023-09-11  6:53                                               ` Dmitry A. Kazakov
2023-09-11 16:13                                                 ` Ben Bacarisse
2023-09-12  7:17                                                   ` Dmitry A. Kazakov
2023-09-13 12:24                                                     ` Ben Bacarisse
2023-09-14  6:33                                                       ` Dmitry A. Kazakov
2023-09-14 14:30                                                         ` Ben Bacarisse
2023-09-08  6:09                               ` G.B.
2023-09-08 21:02                                 ` Ben Bacarisse
2023-09-09  8:13                                   ` G.B.
2023-09-09 21:04                                     ` Ben Bacarisse
2023-09-10  9:11                                     ` Dmitry A. Kazakov
2023-09-05 17:35                 ` moi
2023-09-04 14:23 ` Dmitry A. Kazakov
2023-09-07  7:31 ` Francesc Rocher
2023-09-15  9:07   ` CSYH (QAQ)
2023-09-19  7:59     ` comp.lang.ada
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox