From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on ip-172-31-65-14.ec2.internal X-Spam-Level: X-Spam-Status: No, score=-3.2 required=3.0 tests=BAYES_00,NICE_REPLY_A, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 Path: eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: "Dmitry A. Kazakov" Newsgroups: comp.lang.ada Subject: Re: project euler 26 Date: Wed, 6 Sep 2023 09:06:31 +0200 Organization: A noiseless patient Spider Message-ID: References: <878r9mudvj.fsf@bsb.me.uk> <87a5u1u1yv.fsf@bsb.me.uk> <8734ztttpc.fsf@bsb.me.uk> <87fs3ssl6v.fsf@bsb.me.uk> <87a5u0rts0.fsf@bsb.me.uk> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit Injection-Date: Wed, 6 Sep 2023 07:06:32 -0000 (UTC) Injection-Info: dont-email.me; posting-host="45219ce80d83fc0bae96dda1999b3d4d"; logging-data="2535259"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19gT7ERQs6i+HK1yqDKuydx+SOHM4oW3xs=" User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Thunderbird/102.15.0 Cancel-Lock: sha1:RZuYPKufC585eEEXZfUcerqeWvY= In-Reply-To: <87a5u0rts0.fsf@bsb.me.uk> Content-Language: en-US Xref: news.eternal-september.org comp.lang.ada:65601 List-Id: On 2023-09-06 03:10, Ben Bacarisse wrote: > "Dmitry A. Kazakov" 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