Partial function application: Difference between revisions

(Add min)
Line 2,047:
((0 2 4 6) (4 8 12 16))
((0 1 4 9) (4 16 36 64))</lang>
 
=={{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.
 
<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</lang>
 
===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:
 
<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</lang>
 
and in a separate file,
 
<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(CType(f, Object), [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</lang>
 
{{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|zkl}}==
Anonymous user