What is the best pattern to curry delegate parameters (using .NET 2.0 or later)?

自作多情 提交于 2019-12-05 01:13:51

If you can use .Net 4, how about tuples?

    ''Create new tuple instance with two items.
    Dim tuple As Tuple(Of Integer, String) = _
        New Tuple(Of Integer, String)(5, "Hello")
    ''Now you only have one argument to curry, packaging both parameters
    ''Access the parameters like this (strongly typed)
    Debug.Print tuple.Item1 '' 5
    Debug.Print tuple.Item2 '' "Hello"

This doesn't avoid the boilerplate requirement for every Func and every possible number of "late" arguments, but I just want to show the "simple" approach is still fairly clean. VB's just a bit verbose for it to seem like it is a useful construct.

Also the current Curry definition doesn't implicitly work without the Of types being explicitly specified in the call :-(

EDIT: Show the implicit option does work for explicit Func variables.

 Option Explicit On 
 Option Strict On
 Option Infer On

 Imports System
 Imports Microsoft.VisualBasic

 Module CurryTest

 Function Test1(ByVal X As String, ByVal Y As String) As String
   Return X & Y
 End Function

 Function Test2(ByVal X As Integer, ByVal Y As Integer) As Integer
   Return X + Y
 End Function

 Function Test3(ByVal X As Integer, ByVal Y As Integer, ByVal Z As String) As String
   Return Z & ":" & CStr(X + Y)
 End Function

 Sub Main()

   Dim Curry1 = Curry(Of String, String, String)(AddressOf Test1, "a")
   Dim Curry2 = Curry(Of Integer, Integer, Integer)(AddressOf Test2, 2)
   Dim Curry3 = Curry(Of Integer, Integer, String, String)(AddressOf Test3, 1, 2)

   Dim f As Func(Of String, String, String) = AddressOf Test1
   Dim g As Func(Of Integer, Integer, Integer) = AddressOf Test2
   Dim h As Func(Of Integer, Integer, String, String) = AddressOf Test3

   Dim Curry4 = Curry(f, "b")
   Dim Curry5 = Curry(g, 3)
   Dim Curry6 = Curry(h, 4, 5)

   Console.WriteLine(Curry1("b"))
   Console.WriteLine(Curry1("c"))

   Console.WriteLine(Curry2(2))
   Console.WriteLine(Curry2(3))

   Console.WriteLine(Curry3("Three"))
   Console.WriteLine(Curry3("3 "))

   Console.WriteLine(Curry4("c"))
   Console.WriteLine(Curry4("d"))

   Console.WriteLine(Curry5(4))
   Console.WriteLine(Curry5(5))

   Console.WriteLine(Curry6("Nine"))
   Console.WriteLine(Curry6("9 "))

 End Sub

 Function Curry(Of T, U, V)(ByVal Fn As Func(Of T, U, V), ByVal Arg As T) As Func(Of U, V)
   Return Function(Arg2 As U)(Fn(Arg,Arg2))
 End Function

 Function Curry(Of T, U, V, W)(ByVal Fn As Func(Of T, U, V, W), ByVal Arg1 As T, ByVal Arg2 As U) As Func(Of V, W)
   Return Function(Arg3 As V)(Fn(Arg1,Arg2,Arg3))
 End Function

 End Module

Check out what ContiniousLinq does. It uses a template to auto generate all the curry functions.

https://github.com/ismell/Continuous-LINQ/blob/master/ContinuousLinq/Expressions/Curry.tt

which results in this

https://github.com/ismell/Continuous-LINQ/blob/master/ContinuousLinq/Expressions/Curry.cs

Maybe you can take the template and modify it to generate some VB ?

Raul

If you would ask me this for C# 4.0, I would say: use the dynamic type.

But the funny thing is that VB has always had support for dynamic typing, if you turn Option Strict Off.

To avoid excessive amounts of boilerplate code, you could try to see if it is possible to make an overload with a variable number of parameters. It will be slower but it is a useful safety net to ensure your code works for any function.

I think you will probably need closures as an implementation detail, but that's OK isn't it?

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!