Schäfer, thanks, that's a lot of practical information. Have you used Haskell <a href="http://www.haskell.org/haskellwiki/Introduction_to_QuickCheck">QuickCheck</a>? It's amazing that such a strictly typed language can do these sorts of things.<div>
<br></div><div>Yes, pointers are probably the only way I can implement this, for now. If at all possible, I'd like to use more idiomatic Pascal code. The only way I managed to write the <a href="https://github.com/mcandre/qc">C port</a> was void* tricks :P but there's only so much you can do without lambdas.<br clear="all">
<div><br></div><div>If I decide to use pointers, what's the syntax for accepting a function pointer (unknown type, unknown arity) and calling the function? In C, you have to know the entire function signature and explicitly cast the pointer to that before you can call it. Does Pascal also require this, or can I just accept a pointer and call it as if it were a normal function call?</div>
<div><br></div><div>Finally, does Pascal have syntax for something like Lisp's (apply f args), or Smalltalk's Block valueWithArguments? Once I get forAll to accept function pointers, and call the functions, I need a way to pass the values to another function (again, unknown types, unknown arity).</div>
<div><br></div>Cheers,<div><br></div><div>Andrew Pennebaker</div><div><a href="http://www.yellosoft.us" target="_blank">www.yellosoft.us</a></div>
<br><div class="gmail_quote">2011/10/18 Roland Schäfer <span dir="ltr"><<a href="mailto:roland.schaefer@fu-berlin.de">roland.schaefer@fu-berlin.de</a>></span><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div class="im">On 10/18/2011 8:10 PM, Andrew Pennebaker wrote:<br>
> Sokol, I'm writing a function GenArray(generator) that returns a random<br>
> array populated by calling the generator function. So the return type of<br>
> GenArray matches "array of" the return type of the generator function, for<br>
> any generator function.<br>
><br>
> E.g., GenArray(GenChar) would return a random string. (Except I don't know<br>
> the syntax for passing function pointers.)<br>
<br>
</div>Sven pointed out yesterday that you cannot achieve in FPC what you want<br>
to achieve. (I haven't used Delphi in a long time and don't know what<br>
exactly anonymous functions are in Delphi, but I strongly tend to trust<br>
his word.) You can't get anonymous but only typed "function pointers"<br>
(cf. also Lukasz mail, second to last paragraph, plus his short mail).<br>
<br>
Since you were asking for hacks... By way of satire(!): To bypass the<br>
need to explicitly define a function type for each data type, you could<br>
give up on types and write a lot of functions like<br>
<br>
function GenChar : Pointer;<br>
function GenString : Pointer;<br>
<br>
The type of all of those can be given as<br>
<br>
type TGen = function : Pointer;<br>
<br>
Generator would have to return an array of Pointer in this scenario.<br>
Then, you could hack your way on from there. Please don't mention my<br>
name, though.<br>
<br>
However, if you're just asking about the syntax for procedural types,<br>
the "Language reference guide" for FPC 2.4.4, section 3.6 (p. 45) has<br>
all the details: <a href="http://www.freepascal.org/docs.var" target="_blank">http://www.freepascal.org/docs.var</a><br>
<div class="im"><br>
> Maybe you could fork my code<br>
<br>
</div>Out of curiosity: Is that the impersonal "you"?<br>
<div class="im"><br>
> and use templates to achieve this?<br>
<br>
</div>Generics are currently for classes only, as chapter 8 (p. 87) of the<br>
aforementioned reference guide explains.<br>
<br>
Best,<br>
<font color="#888888">Roland<br>
</font><div><div></div><div class="h5"><br>
> On Tue, Oct 18, 2011 at 4:57 AM, Lukasz Sokol <<a href="mailto:el.es.cr@gmail.com">el.es.cr@gmail.com</a>> wrote:<br>
><br>
>> On 17/10/2011 21:53, Andrew Pennebaker wrote:<br>
>>> Does Free Pascal have anonymous functions that you can pass around,<br>
>>> e.g. to a sort(compare : function, arr : array) function?<br>
>>><br>
>>> If not, does anyone know any hacks to accomplish this?<br>
>>><br>
>>> Cheers,<br>
>>><br>
>>> Andrew Pennebaker <a href="http://www.yellosoft.us" target="_blank">www.yellosoft.us</a> <<a href="http://www.yellosoft.us" target="_blank">http://www.yellosoft.us</a>><br>
>>><br>
>><br>
>> Yes:<br>
>><br>
>> //you can declare a type :<br>
>><br>
>> TMyFunction: function(AMyParam : TType): TOtherType;<br>
>><br>
>> // then implement:<br>
>><br>
>> function MyFunctionWithArbitraryName(AMyParam: TType): TOtherType;<br>
>> begin<br>
>> {do something with AMyParam}<br>
>> end;<br>
>><br>
>> //then (or before, if the TMyFunction is in type declaration section)<br>
>><br>
>> function AFunctionUsingTMyFunctionAsArgument(AFunction :<br>
>> TMyFunction):TWhateverType;<br>
>> var OtherReturn: TOtherType;<br>
>> AParameterToAFunction : TType;<br>
>> begin<br>
>> {some code}<br>
>> OtherReturn := AFunction(AParameter);<br>
>> {other code}<br>
>> end;<br>
>><br>
>> // and finally even<br>
>> const MYFUNCTIONCOUNT = 1<br>
>> ArrayOfTMyFunction = array[0..MYFUNCTIONCOUNT-1] of TMyFunction =<br>
>> (MyFunctionWithArbitraryName);<br>
>> {it's a static array, so<br>
>> match the number of elemets}<br>
>><br>
>> begin<br>
>> for {declared somewhere global} i := 0 to MYFUNCTIONCOUNT-1 do<br>
>> WhateverReturn :=<br>
>> AFunctionUsingTMyFunctionAsArgument(ArrayOfTMyFunction[i](MyParam));<br>
>><br>
>> end.<br>
>><br>
>> (Terms and conditions : this is invoked from /dev/mem, some syntax<br>
>> discrepancies may occur<br>
>> as my attention moved on from this as it obviously worked)<br>
>><br>
>> I have written a dumb CLI interpreter this way ;) recently.<br>
>> (the function table contains command name as string in a record together<br>
>> with the function<br>
>> and the main procedure looks for the name and executes the arbitrary<br>
>> function when found)<br>
>><br>
>> TMyFunctionRecord = record<br>
>> CLIName: string;<br>
>> MyFunction : TMyFunction<br>
>> end;<br>
>><br>
>> const ArrayOfCLIFunctions = array[0..CLIFUNCCOUNT-1] of TMyFunctionRecord =<br>
>> ({...});<br>
>><br>
>> var CLIFunctionToExecute : TMyFunction;<br>
>> WhateverReturn : TWhateverType;<br>
>><br>
>> begin<br>
>> for i := 0 to CLIFUNCCOUNT-1 do<br>
>> if ArrayOfCLIFunctions[i].CLIName = paramstr[1] then<br>
>> begin<br>
>> CLIFunctionToExecute := ArrayOfCLIFunctions[i].MyFunction;<br>
>> break;<br>
>> end;<br>
>> WhateverReturn :=<br>
>> AFunctionUsingTMyFunctionAsArgument(CLIFunctionToExecute(MyParam));<br>
>> end.<br>
>><br>
>><br>
>> Also the 'anonymous' functions can be implemented in a separate unit which<br>
>> only exports the<br>
>> /relevant/ ones in its interface section.<br>
>><br>
>> The obvious limitation / safeguard is : you must use the function of<br>
>> declared type to pass into<br>
>> the function AFunctionUsingTMyFunctionAsArgument(AFunction : TMyFunction)<br>
>> and no other type;<br>
>> (An obvious workaround to that is to use varargs ;) but I did not try that<br>
>> so I can't tell<br>
>> whether that would work)<br>
>><br>
>> It's not much OOP in action (and may have {obvious for some //not me}<br>
>> performance penalties but oh well. ;)<br>
>><br>
>> L.<br>
>><br>
_______________________________________________<br>
fpc-pascal maillist - <a href="mailto:fpc-pascal@lists.freepascal.org">fpc-pascal@lists.freepascal.org</a><br>
<a href="http://lists.freepascal.org/mailman/listinfo/fpc-pascal" target="_blank">http://lists.freepascal.org/mailman/listinfo/fpc-pascal</a><br>
</div></div></blockquote></div><br></div>