Currying: Difference between revisions

Content added Content deleted
(Dialects of BASIC moved to the BASIC section.)
Line 274: Line 274:
<pre>9
<pre>9
10</pre>
10</pre>

=={{header|BASIC}}==
==={{header|FreeBASIC}}===
FreeBASIC is not a functional language and does not support either currying or nested functions/lambdas which are typically used by otherwise imperative languages to implement the former. The nearest I could get to currying using the features which the language does support is the following:
<syntaxhighlight lang="freebasic">' FB 1.05.0 Win64

Type CurriedAdd
As Integer i
Declare Function add(As Integer) As Integer
End Type

Function CurriedAdd.add(j As Integer) As Integer
Return i + j
End Function

Function add (i As Integer) as CurriedAdd
Return Type<CurriedAdd>(i)
End Function

Print "3 + 4 ="; add(3).add(4)
Print "2 + 6 ="; add(2).add(6)
Sleep</syntaxhighlight>

{{out}}
<pre>
3 + 4 = 7
2 + 6 = 8
</pre>

==={{header|Visual Basic .NET}}===
'''Compiler:''' Roslyn Visual Basic (language version >=15.3)

Functions are not curried in VB.NET, so this entry details functions that take a function and return functions that act as if the original function were curried (i.e. each takes one parameter and returns another function that takes one parameter, with the function for which all parameters of the original function are supplied calling the original function with those arguments.

====Fixed-arity approach====
Uses generics and lambdas returning lambdas.
<syntaxhighlight lang="vbnet">Option Explicit On
Option Infer On
Option Strict On

Module Currying
' The trivial curry.
Function Curry(Of T1, TResult)(func As Func(Of T1, TResult)) As Func(Of T1, TResult)
' At least satisfy the implicit contract that the result isn't reference-equal to the original function.
Return Function(a) func(a)
End Function

Function Curry(Of T1, T2, TResult)(func As Func(Of T1, T2, TResult)) As Func(Of T1, Func(Of T2, TResult))
Return Function(a) Function(b) func(a, b)
End Function

Function Curry(Of T1, T2, T3, TResult)(func As Func(Of T1, T2, T3, TResult)) As Func(Of T1, Func(Of T2, Func(Of T3, TResult)))
Return Function(a) Function(b) Function(c) func(a, b, c)
End Function

' And so on.
End Module</syntaxhighlight>

Test code:
<syntaxhighlight lang="vbnet">Module Main
' An example binary function.
Function Add(a As Integer, b As Integer) As Integer
Return a + b
End Function

Sub Main()
Dim curriedAdd = Curry(Of Integer, Integer, Integer)(AddressOf Add)
Dim add2To = curriedAdd(2)

Console.WriteLine(Add(2, 3))
Console.WriteLine(add2To(3))
Console.WriteLine(curriedAdd(2)(3))

' An example ternary function.
Dim substring = Function(s As String, startIndex As Integer, length As Integer) s.Substring(startIndex, length)
Dim curriedSubstring = Curry(substring)

Console.WriteLine(substring("abcdefg", 2, 3))
Console.WriteLine(curriedSubstring("abcdefg")(2)(3))

' The above is just syntax sugar for this (a call to the Invoke() method of System.Delegate):
Console.WriteLine(curriedSubstring.Invoke("abcdefg").Invoke(2).Invoke(3))

Dim substringStartingAt1 = curriedSubstring("abcdefg")(1)
Console.WriteLine(substringStartingAt1(2))
Console.WriteLine(substringStartingAt1(4))
End Sub
End Module</syntaxhighlight>

====Late-binding approach====

{{libheader|.NET Core|2=>=1.0}}
or both
{{libheader|.NET Framework|2=>=4.5}}
and
{{libheader|System.Collections.Immutable|1.5.0}}

Due to VB's syntax, with indexers using parentheses, late-bound invocation expressions are compiled as invocations of the default property of the receiver. Thus, it is not possible to perform a late-bound delegate invocation. This limitation can, however, be circumvented, by declaring a type that wraps a delegate and defines a default property that invokes the delegate. Furthermore, by making this type what is essentially a discriminated union of a delegate and a result and guaranteeing that all invocations return another instance of this type, it is possible for the entire system to work with Option Strict on.

<syntaxhighlight lang="vbnet">Option Explicit On
Option Infer On
Option Strict On

Module CurryingDynamic
' Cheat visual basic's syntax by defining a type that can be the receiver of what appears to be a method call.
' Needless to say, this is not idiomatic VB.
Class CurryDelegate
ReadOnly Property Value As Object
ReadOnly Property Target As [Delegate]

Sub New(value As Object)
Dim curry = TryCast(value, CurryDelegate)
If curry IsNot Nothing Then
Me.Value = curry.Value
Me.Target = curry.Target
ElseIf TypeOf value Is [Delegate] Then
Me.Target = DirectCast(value, [Delegate])
Else
Me.Value = value
End If
End Sub

' CurryDelegate could also work as a dynamic n-ary function delegate, if an additional ParamArray argument were to be added.
Default ReadOnly Property Invoke(arg As Object) As CurryDelegate
Get
If Me.Target Is Nothing Then Throw New InvalidOperationException("All curried parameters have already been supplied")

Return New CurryDelegate(Me.Target.DynamicInvoke({arg}))
End Get
End Property

' A syntactically natural way to assert that the currying is complete and that the result is of the specified type.
Function Unwrap(Of T)() As T
If Me.Target IsNot Nothing Then Throw New InvalidOperationException("Some curried parameters have not yet been supplied.")
Return DirectCast(Me.Value, T)
End Function
End Class

Function DynamicCurry(func As [Delegate]) As CurryDelegate
Return DynamicCurry(func, ImmutableList(Of Object).Empty)
End Function

' Use ImmutableList to create a new list every time any curried subfunction is called avoiding multiple or repeated
' calls interfering with each other.
Private Function DynamicCurry(func As [Delegate], collectedArgs As ImmutableList(Of Object)) As CurryDelegate
Return If(collectedArgs.Count = func.Method.GetParameters().Length,
New CurryDelegate(func.DynamicInvoke(collectedArgs.ToArray())),
New CurryDelegate(Function(arg As Object) DynamicCurry(func, collectedArgs.Add(arg))))
End Function
End Module</syntaxhighlight>

Test code:
<syntaxhighlight lang="vbnet">Module Program
Function Add(a As Integer, b As Integer) As Integer
Return a + b
End Function

Sub Main()
' A delegate for the function must be created in order to eagerly perform overload resolution.
Dim curriedAdd = DynamicCurry(New Func(Of Integer, Integer, Integer)(AddressOf Add))
Dim add2To = curriedAdd(2)

Console.WriteLine(add2To(3).Unwrap(Of Integer))
Console.WriteLine(curriedAdd(2)(3).Unwrap(Of Integer))

Dim substring = Function(s As String, i1 As Integer, i2 As Integer) s.Substring(i1, i2)
Dim curriedSubstring = DynamicCurry(substring)

Console.WriteLine(substring("abcdefg", 2, 3))
Console.WriteLine(curriedSubstring("abcdefg")(2)(3).Unwrap(Of String))

' The trickery of using a parameterized default property also makes it appear that the "delegate" has an Invoke() method.
Console.WriteLine(curriedSubstring.Invoke("abcdefg").Invoke(2).Invoke(3).Unwrap(Of String))

Dim substringStartingAt1 = curriedSubstring("abcdefg")(1)
Console.WriteLine(substringStartingAt1(2).Unwrap(Of String))
Console.WriteLine(substringStartingAt1(4).Unwrap(Of String))
End Sub
End Module
</syntaxhighlight>

{{out|note=for both versions}}
<pre>5
5
5
cde
cde
cde
bc
bcde</pre>


=={{header|BQN}}==
=={{header|BQN}}==
Line 729: Line 919:
<pre>10 12</pre>
<pre>10 12</pre>


=={{header|FreeBASIC}}==
FreeBASIC is not a functional language and does not support either currying or nested functions/lambdas which are typically used by otherwise imperative languages to implement the former. The nearest I could get to currying using the features which the language does support is the following:
<syntaxhighlight lang="freebasic">' FB 1.05.0 Win64

Type CurriedAdd
As Integer i
Declare Function add(As Integer) As Integer
End Type

Function CurriedAdd.add(j As Integer) As Integer
Return i + j
End Function

Function add (i As Integer) as CurriedAdd
Return Type<CurriedAdd>(i)
End Function

Print "3 + 4 ="; add(3).add(4)
Print "2 + 6 ="; add(2).add(6)
Sleep</syntaxhighlight>

{{out}}
<pre>
3 + 4 = 7
2 + 6 = 8
</pre>


=={{header|Fōrmulæ}}==
=={{header|Fōrmulæ}}==
Line 2,204: Line 2,368:
9
9
</pre>
</pre>

=={{header|Visual Basic .NET}}==
'''Compiler:''' Roslyn Visual Basic (language version >=15.3)

Functions are not curried in VB.NET, so this entry details functions that take a function and return functions that act as if the original function were curried (i.e. each takes one parameter and returns another function that takes one parameter, with the function for which all parameters of the original function are supplied calling the original function with those arguments.

===Fixed-arity approach===

Uses generics and lambdas returning lambdas.

<syntaxhighlight lang="vbnet">Option Explicit On
Option Infer On
Option Strict On

Module Currying
' The trivial curry.
Function Curry(Of T1, TResult)(func As Func(Of T1, TResult)) As Func(Of T1, TResult)
' At least satisfy the implicit contract that the result isn't reference-equal to the original function.
Return Function(a) func(a)
End Function

Function Curry(Of T1, T2, TResult)(func As Func(Of T1, T2, TResult)) As Func(Of T1, Func(Of T2, TResult))
Return Function(a) Function(b) func(a, b)
End Function

Function Curry(Of T1, T2, T3, TResult)(func As Func(Of T1, T2, T3, TResult)) As Func(Of T1, Func(Of T2, Func(Of T3, TResult)))
Return Function(a) Function(b) Function(c) func(a, b, c)
End Function

' And so on.
End Module</syntaxhighlight>

Test code:
<syntaxhighlight lang="vbnet">Module Main
' An example binary function.
Function Add(a As Integer, b As Integer) As Integer
Return a + b
End Function

Sub Main()
Dim curriedAdd = Curry(Of Integer, Integer, Integer)(AddressOf Add)
Dim add2To = curriedAdd(2)

Console.WriteLine(Add(2, 3))
Console.WriteLine(add2To(3))
Console.WriteLine(curriedAdd(2)(3))

' An example ternary function.
Dim substring = Function(s As String, startIndex As Integer, length As Integer) s.Substring(startIndex, length)
Dim curriedSubstring = Curry(substring)

Console.WriteLine(substring("abcdefg", 2, 3))
Console.WriteLine(curriedSubstring("abcdefg")(2)(3))

' The above is just syntax sugar for this (a call to the Invoke() method of System.Delegate):
Console.WriteLine(curriedSubstring.Invoke("abcdefg").Invoke(2).Invoke(3))

Dim substringStartingAt1 = curriedSubstring("abcdefg")(1)
Console.WriteLine(substringStartingAt1(2))
Console.WriteLine(substringStartingAt1(4))
End Sub
End Module</syntaxhighlight>

===Late-binding approach===

{{libheader|.NET Core|2=>=1.0}}
or both
{{libheader|.NET Framework|2=>=4.5}}
and
{{libheader|System.Collections.Immutable|1.5.0}}

Due to VB's syntax, with indexers using parentheses, late-bound invocation expressions are compiled as invocations of the default property of the receiver. Thus, it is not possible to perform a late-bound delegate invocation. This limitation can, however, be circumvented, by declaring a type that wraps a delegate and defines a default property that invokes the delegate. Furthermore, by making this type what is essentially a discriminated union of a delegate and a result and guaranteeing that all invocations return another instance of this type, it is possible for the entire system to work with Option Strict on.

<syntaxhighlight lang="vbnet">Option Explicit On
Option Infer On
Option Strict On

Module CurryingDynamic
' Cheat visual basic's syntax by defining a type that can be the receiver of what appears to be a method call.
' Needless to say, this is not idiomatic VB.
Class CurryDelegate
ReadOnly Property Value As Object
ReadOnly Property Target As [Delegate]

Sub New(value As Object)
Dim curry = TryCast(value, CurryDelegate)
If curry IsNot Nothing Then
Me.Value = curry.Value
Me.Target = curry.Target
ElseIf TypeOf value Is [Delegate] Then
Me.Target = DirectCast(value, [Delegate])
Else
Me.Value = value
End If
End Sub

' CurryDelegate could also work as a dynamic n-ary function delegate, if an additional ParamArray argument were to be added.
Default ReadOnly Property Invoke(arg As Object) As CurryDelegate
Get
If Me.Target Is Nothing Then Throw New InvalidOperationException("All curried parameters have already been supplied")

Return New CurryDelegate(Me.Target.DynamicInvoke({arg}))
End Get
End Property

' A syntactically natural way to assert that the currying is complete and that the result is of the specified type.
Function Unwrap(Of T)() As T
If Me.Target IsNot Nothing Then Throw New InvalidOperationException("Some curried parameters have not yet been supplied.")
Return DirectCast(Me.Value, T)
End Function
End Class

Function DynamicCurry(func As [Delegate]) As CurryDelegate
Return DynamicCurry(func, ImmutableList(Of Object).Empty)
End Function

' Use ImmutableList to create a new list every time any curried subfunction is called avoiding multiple or repeated
' calls interfering with each other.
Private Function DynamicCurry(func As [Delegate], collectedArgs As ImmutableList(Of Object)) As CurryDelegate
Return If(collectedArgs.Count = func.Method.GetParameters().Length,
New CurryDelegate(func.DynamicInvoke(collectedArgs.ToArray())),
New CurryDelegate(Function(arg As Object) DynamicCurry(func, collectedArgs.Add(arg))))
End Function
End Module</syntaxhighlight>

Test code:
<syntaxhighlight lang="vbnet">Module Program
Function Add(a As Integer, b As Integer) As Integer
Return a + b
End Function

Sub Main()
' A delegate for the function must be created in order to eagerly perform overload resolution.
Dim curriedAdd = DynamicCurry(New Func(Of Integer, Integer, Integer)(AddressOf Add))
Dim add2To = curriedAdd(2)

Console.WriteLine(add2To(3).Unwrap(Of Integer))
Console.WriteLine(curriedAdd(2)(3).Unwrap(Of Integer))

Dim substring = Function(s As String, i1 As Integer, i2 As Integer) s.Substring(i1, i2)
Dim curriedSubstring = DynamicCurry(substring)

Console.WriteLine(substring("abcdefg", 2, 3))
Console.WriteLine(curriedSubstring("abcdefg")(2)(3).Unwrap(Of String))

' The trickery of using a parameterized default property also makes it appear that the "delegate" has an Invoke() method.
Console.WriteLine(curriedSubstring.Invoke("abcdefg").Invoke(2).Invoke(3).Unwrap(Of String))

Dim substringStartingAt1 = curriedSubstring("abcdefg")(1)
Console.WriteLine(substringStartingAt1(2).Unwrap(Of String))
Console.WriteLine(substringStartingAt1(4).Unwrap(Of String))
End Sub
End Module
</syntaxhighlight>

{{out|note=for both versions}}
<pre>5
5
5
cde
cde
cde
bc
bcde</pre>


=={{header|Wortel}}==
=={{header|Wortel}}==