Partial function application: Difference between revisions

Added FreeBASIC
m (→‎{{header|Perl}}: future-proof for 5.36, explicit :prototype)
(Added FreeBASIC)
 
(4 intermediate revisions by 4 users not shown)
Line 232:
<pre>{{0, 2, 4, 6}, {0, 1, 4, 9}, {4, 8, 12, 16}, {4, 16, 36, 64}}</pre>
 
=={{header|BBC BASIC}}==
==={{header|BBC BASIC}}===
{{works with|BBC BASIC for Windows}}
<syntaxhighlight lang="bbcbasic"> fsf1 = FNpartial(PROCfs(), FNf1())
Line 284 ⟶ 285:
4 16 36 64
</pre>
 
==={{header|FreeBASIC}}===
{{trans|Lua}}
<syntaxhighlight lang="vbnet">Sub map(f As Function(As Integer) As Integer, arr() As Integer, result() As Integer)
For i As Integer = Lbound(arr) To Ubound(arr)
result(i) = f(arr(i))
Next i
End Sub
 
Function timestwo(n As Integer) As Integer
Return n * 2
End Function
 
Function squared(n As Integer) As Integer
Return n ^ 2
End Function
 
Sub printArray(arr() As Integer)
For i As Integer = Lbound(arr) To Ubound(arr)
Print arr(i);
If i < Ubound(arr) Then Print ",";
Next i
Print
End Sub
 
Dim As Integer arr1(3) = {0, 1, 2, 3}
Dim As Integer arr2(3) = {2, 4, 6, 8}
Dim As Integer result(3)
 
map(@timestwo, arr1(), result())
printArray(result())
 
map(@squared, arr1(), result())
printArray(result())
 
map(@timestwo, arr2(), result())
printArray(result())
 
map(@squared, arr2(), result())
printArray(result())
 
Sleep</syntaxhighlight>
{{out}}
<pre>Same as Lua entry.</pre>
 
==={{header|Visual Basic .NET}}===
Functions are not curried in VB, and so this entry details the creation of functions that take a function and one or more arguments and returns a function that is the result of the partial application of the given function to those arguments.
 
This is done with two approaches: one that takes generic functions of fixed arity and returns a lambda that then calls the function, and a generalized one that allows arbitrary arity of function and arguments.
 
====First approach====
The "type-safe" approach, which has the disadvantage that a new overload of PartialApply must be created for every combination of function arity and applied argument arity.
 
<syntaxhighlight lang="vbnet">Module PartialApplication
Function fs(Of TSource, TResult)(f As Func(Of TSource, TResult), s As IEnumerable(Of TSource)) As IEnumerable(Of TResult)
' This is exactly what Enumerable.Select does.
Return s.Select(f)
End Function
 
Function f1(x As Integer) As Integer
Return x * 2
End Function
 
Function f2(x As Integer) As Integer
Return x * x
End Function
 
' The overload that takes a binary function and partially applies to its first parameter.
Function PartialApply(Of T1, T2, TResult)(f As Func(Of T1, T2, TResult), arg As T1) As Func(Of T2, TResult)
Return Function(arg2) f(arg, arg2)
End Function
 
Sub Main()
Dim args1 As Integer() = {0, 1, 2, 3}
Dim args2 As Integer() = {2, 4, 6, 8}
 
Dim fsf1 = PartialApply(Of Func(Of Integer, Integer), IEnumerable(Of Integer), IEnumerable(Of Integer))(AddressOf fs, AddressOf f1)
Dim fsf2 = PartialApply(Of Func(Of Integer, Integer), IEnumerable(Of Integer), IEnumerable(Of Integer))(AddressOf fs, AddressOf f2)
 
Console.WriteLine("fsf1, 0-3: " & String.Join(", ", fsf1(args1)))
Console.WriteLine("fsf1, evens: " & String.Join(", ", fsf1(args2)))
Console.WriteLine("fsf2, 0-3: " & String.Join(", ", fsf2(args1)))
Console.WriteLine("fsf2, evens: " & String.Join(", ", fsf2(args2)))
End Sub
End Module</syntaxhighlight>
 
====Second approach====
f1 and f2 in the second approach will also be defined to use late binding in order to work with any argument that can be multiplied. In the interest of idiomatic VB.NET, a minimal amount of code is to have Option Strict off:
 
<syntaxhighlight lang="vbnet">Option Strict Off
 
Partial Module PartialApplicationDynamic
Function f1(x As Object) As Object
Return x * 2
End Function
 
Function f2(x As Object) As Object
Return x * x
End Function
End Module</syntaxhighlight>
 
and in a separate file,
 
<syntaxhighlight lang="vbnet">Option Strict On
 
Partial Module PartialApplicationDynamic
' Create a matching delegate type to simplify delegate creation.
Delegate Function fsDelegate(Of TSource, TResult)(f As Func(Of TSource, TResult), s As IEnumerable(Of TSource)) As IEnumerable(Of TResult)
Function fs(Of TSource, TResult)(f As Func(Of TSource, TResult), s As IEnumerable(Of TSource)) As IEnumerable(Of TResult)
' This is exactly what Enumerable.Select does.
Return s.Select(f)
End Function
 
Function ArrayConcat(Of T)(arr1 As T(), arr2 As T()) As T()
Dim result(arr1.Length + arr2.Length - 1) As T
Array.Copy(arr1, result, arr1.Length)
Array.Copy(arr2, 0, result, 1, arr2.Length)
Return result
End Function
 
' C# can define ParamArray delegates and VB can consume them, but VB cannot define them on its own.
' The argument list of calls to the resulting function thus must be wrapped in a coerced array literal.
' VB also doesn't allow Delegate as a type constraint. :(
' The function is generic solely to ease use for callers. In this case generics aren't providing any type-safety.
Function PartialApplyDynamic(Of TDelegate, TResult)(f As TDelegate, ParamArray args As Object()) As Func(Of Object(), TResult)
Dim del = CType(CObj(f), [Delegate])
Return Function(rest) CType(del.DynamicInvoke(ArrayConcat(args, rest).Cast(Of Object).ToArray()), TResult)
End Function
 
Sub Main()
Dim args1 As Object = New Object() {0, 1, 2, 3}
Dim args2 As Object = New Object() {2, 4, 6, 8}
 
Dim fsf1 = PartialApplyDynamic(Of fsDelegate(Of Object, Object), IEnumerable(Of Object))(AddressOf fs, New Func(Of Object, Object)(AddressOf f1))
Dim fsf2 = PartialApplyDynamic(Of fsDelegate(Of Object, Object), IEnumerable(Of Object))(AddressOf fs, New Func(Of Object, Object)(AddressOf f2))
 
' The braces are array literals.
Console.WriteLine("fsf1, 0-3: " & String.Join(", ", fsf1({args1})))
Console.WriteLine("fsf1, evens: " & String.Join(", ", fsf1({args2})))
Console.WriteLine("fsf2, 0-3: " & String.Join(", ", fsf2({args1})))
Console.WriteLine("fsf2, evens: " & String.Join(", ", fsf2({args2})))
End Sub
End Module</syntaxhighlight>
 
{{out|note=for both versions}}
<pre>fsf1, 0-3: 0, 2, 4, 6
fsf1, evens: 4, 8, 12, 16
fsf2, 0-3: 0, 1, 4, 9
fsf2, evens: 4, 16, 36, 64</pre>
 
=={{header|Bracmat}}==
Line 723 ⟶ 873:
=={{header|Elena}}==
{{trans|Smalltalk}}
ELENA 56.0x :
<syntaxhighlight lang="elena">import system'collections;
import system'routines;
Line 732 ⟶ 882:
var partial := (afs,af => (s => afs(af, s)));
var fs := (f,s => s.selectBy::(x => f(x)).summarize(new ArrayList()).toArray());
var f1 := (x => x * 2);
var f2 := (x => x * x);
Line 2,147 ⟶ 2,297:
for f1, series= 2 4 6 8, result= 4 8 12 16
for f2, series= 2 4 6 8, result= 4 16 36 64
</pre>
 
=={{header|RPL}}==
<code>fs(f,s)</code> is a built-in function in RPL named <code>DOLIST </code>
« 2 * » '<span style="color:blue">F1</span>' STO
« SQ » '<span style="color:blue">F2</span>' STO
« 1 '<span style="color:blue">F1</span>' DOLIST » '<span style="color:blue">FSF1</span>' STO
« 1 '<span style="color:blue">F2</span>' DOLIST » '<span style="color:blue">FSF2</span>' STO
 
{ 0 1 2 3 } <span style="color:blue">FSF1</span>
{ 0 1 2 3 } <span style="color:blue">FSF2</span>
{ 2 4 6 8 } <span style="color:blue">FSF1</span>
{ 2 4 6 8 } <span style="color:blue">FSF2</span>
{{out}}
<pre>
4: { 0 2 4 6 }
3! { 0 1 4 9 }
2: { 4 8 12 16 }
1: { 4 16 36 64 }
</pre>
 
Line 2,297 ⟶ 2,469:
((0 2 4 6) (4 8 12 16))
((0 1 4 9) (4 16 36 64))</syntaxhighlight>
 
=={{header|Visual Basic .NET}}==
 
Functions are not curried in VB, and so this entry details the creation of functions that take a function and one or more arguments and returns a function that is the result of the partial application of the given function to those arguments.
 
This is done with two approaches: one that takes generic functions of fixed arity and returns a lambda that then calls the function, and a generalized one that allows arbitrary arity of function and arguments.
 
===First approach===
 
The "type-safe" approach, which has the disadvantage that a new overload of PartialApply must be created for every combination of function arity and applied argument arity.
 
<syntaxhighlight lang="vbnet">Module PartialApplication
Function fs(Of TSource, TResult)(f As Func(Of TSource, TResult), s As IEnumerable(Of TSource)) As IEnumerable(Of TResult)
' This is exactly what Enumerable.Select does.
Return s.Select(f)
End Function
 
Function f1(x As Integer) As Integer
Return x * 2
End Function
 
Function f2(x As Integer) As Integer
Return x * x
End Function
 
' The overload that takes a binary function and partially applies to its first parameter.
Function PartialApply(Of T1, T2, TResult)(f As Func(Of T1, T2, TResult), arg As T1) As Func(Of T2, TResult)
Return Function(arg2) f(arg, arg2)
End Function
 
Sub Main()
Dim args1 As Integer() = {0, 1, 2, 3}
Dim args2 As Integer() = {2, 4, 6, 8}
 
Dim fsf1 = PartialApply(Of Func(Of Integer, Integer), IEnumerable(Of Integer), IEnumerable(Of Integer))(AddressOf fs, AddressOf f1)
Dim fsf2 = PartialApply(Of Func(Of Integer, Integer), IEnumerable(Of Integer), IEnumerable(Of Integer))(AddressOf fs, AddressOf f2)
 
Console.WriteLine("fsf1, 0-3: " & String.Join(", ", fsf1(args1)))
Console.WriteLine("fsf1, evens: " & String.Join(", ", fsf1(args2)))
Console.WriteLine("fsf2, 0-3: " & String.Join(", ", fsf2(args1)))
Console.WriteLine("fsf2, evens: " & String.Join(", ", fsf2(args2)))
End Sub
End Module</syntaxhighlight>
 
===Second approach===
 
f1 and f2 in the second approach will also be defined to use late binding in order to work with any argument that can be multiplied. In the interest of idiomatic VB.NET, a minimal amount of code is to have Option Strict off:
 
<syntaxhighlight lang="vbnet">Option Strict Off
 
Partial Module PartialApplicationDynamic
Function f1(x As Object) As Object
Return x * 2
End Function
 
Function f2(x As Object) As Object
Return x * x
End Function
End Module</syntaxhighlight>
 
and in a separate file,
 
<syntaxhighlight lang="vbnet">Option Strict On
 
Partial Module PartialApplicationDynamic
' Create a matching delegate type to simplify delegate creation.
Delegate Function fsDelegate(Of TSource, TResult)(f As Func(Of TSource, TResult), s As IEnumerable(Of TSource)) As IEnumerable(Of TResult)
Function fs(Of TSource, TResult)(f As Func(Of TSource, TResult), s As IEnumerable(Of TSource)) As IEnumerable(Of TResult)
' This is exactly what Enumerable.Select does.
Return s.Select(f)
End Function
 
Function ArrayConcat(Of T)(arr1 As T(), arr2 As T()) As T()
Dim result(arr1.Length + arr2.Length - 1) As T
Array.Copy(arr1, result, arr1.Length)
Array.Copy(arr2, 0, result, 1, arr2.Length)
Return result
End Function
 
' C# can define ParamArray delegates and VB can consume them, but VB cannot define them on its own.
' The argument list of calls to the resulting function thus must be wrapped in a coerced array literal.
' VB also doesn't allow Delegate as a type constraint. :(
' The function is generic solely to ease use for callers. In this case generics aren't providing any type-safety.
Function PartialApplyDynamic(Of TDelegate, TResult)(f As TDelegate, ParamArray args As Object()) As Func(Of Object(), TResult)
Dim del = CType(CObj(f), [Delegate])
Return Function(rest) CType(del.DynamicInvoke(ArrayConcat(args, rest).Cast(Of Object).ToArray()), TResult)
End Function
 
Sub Main()
Dim args1 As Object = New Object() {0, 1, 2, 3}
Dim args2 As Object = New Object() {2, 4, 6, 8}
 
Dim fsf1 = PartialApplyDynamic(Of fsDelegate(Of Object, Object), IEnumerable(Of Object))(AddressOf fs, New Func(Of Object, Object)(AddressOf f1))
Dim fsf2 = PartialApplyDynamic(Of fsDelegate(Of Object, Object), IEnumerable(Of Object))(AddressOf fs, New Func(Of Object, Object)(AddressOf f2))
 
' The braces are array literals.
Console.WriteLine("fsf1, 0-3: " & String.Join(", ", fsf1({args1})))
Console.WriteLine("fsf1, evens: " & String.Join(", ", fsf1({args2})))
Console.WriteLine("fsf2, 0-3: " & String.Join(", ", fsf2({args1})))
Console.WriteLine("fsf2, evens: " & String.Join(", ", fsf2({args2})))
End Sub
End Module</syntaxhighlight>
 
{{out|note=for both versions}}
<pre>fsf1, 0-3: 0, 2, 4, 6
fsf1, evens: 4, 8, 12, 16
fsf2, 0-3: 0, 1, 4, 9
fsf2, evens: 4, 16, 36, 64</pre>
 
=={{header|Wren}}==
<syntaxhighlight lang="ecmascriptwren">var fs = Fn.new { |f, s| s.map { |e| f.call(e) }.toList }
var f1 = Fn.new { |n| 2 * n }
var f2 = Fn.new { |n| n * n }
2,122

edits