假设有一个用FSharp编写的第三方库,它包含几个通用类,例如以下内容:
- 类型 FirstType<'a> 有一个方法 DoWork,接受: - 第一个参数是类型为 FirstType<'a> 的对象, - 第二个参数是一个函数,其类型为 ('a -> 'b)。 - DoWork 方法的返回类型是 FirstType<'b>。
- 类型 SecondType<'a> 有一个方法 DoWork,接受: - 第一个参数是类型为 SecondType<'a> 的对象, - 第二个参数是一个函数,其类型为 ('a -> 'b)。 - DoWork 方法的返回类型是 SecondType<'b>。
- 类型 ThirdType<'a> 有一个方法 DoWork,接受: - 第一个参数是类型为 ThirdType<'a> 的对象, - 第二个参数是一个函数,其类型为 ('a -> 'b)。 - DoWork 方法的返回类型是 ThirdType<'b>。
这些类没有共同的接口或父类,Object 是它们唯一的共同父类。
下面的每种类型都有一个名为 DoWork 的方法。它接受两个参数:
- 第一个参数是包含 DoWork 方法的类的类型。 - 第二个参数是一个函数,它接受与类的泛型参数相等的参数,并返回任何类型的元素 'b。
然后,该 DoWork 函数应返回具有与其所在类相同的类型的对象,但泛型类型参数等于 'b。
目前,这些类的用法示例如下:
我曾考虑过函数重载,但在F#中不允许使用。现在我在思考如何使函数返回真正不同的类型,而不是辨别联合类型,因为在调用函数时它期望一个特定的类型。
更新:我已经看了John Palmer的评论并尝试了它。
尝试创建函数时:
重新设计具有元组形式参数的Ops类型中的Do方法,并创建如下的Do函数时:
- 类型 FirstType<'a> 有一个方法 DoWork,接受: - 第一个参数是类型为 FirstType<'a> 的对象, - 第二个参数是一个函数,其类型为 ('a -> 'b)。 - DoWork 方法的返回类型是 FirstType<'b>。
- 类型 SecondType<'a> 有一个方法 DoWork,接受: - 第一个参数是类型为 SecondType<'a> 的对象, - 第二个参数是一个函数,其类型为 ('a -> 'b)。 - DoWork 方法的返回类型是 SecondType<'b>。
- 类型 ThirdType<'a> 有一个方法 DoWork,接受: - 第一个参数是类型为 ThirdType<'a> 的对象, - 第二个参数是一个函数,其类型为 ('a -> 'b)。 - DoWork 方法的返回类型是 ThirdType<'b>。
这些类没有共同的接口或父类,Object 是它们唯一的共同父类。
下面的每种类型都有一个名为 DoWork 的方法。它接受两个参数:
- 第一个参数是包含 DoWork 方法的类的类型。 - 第二个参数是一个函数,它接受与类的泛型参数相等的参数,并返回任何类型的元素 'b。
然后,该 DoWork 函数应返回具有与其所在类相同的类型的对象,但泛型类型参数等于 'b。
目前,这些类的用法示例如下:
let first = new FirstType<int>()
...
// here result is of type FirstType<string>
let result = FirstType.DoWork first (fun x -> "hello" + x.toString())
let second = new SecondType<int>()
...
// here result is of type SecondType<bool>
let result = SecondType.DoWork second (fun x -> 2 = 4)
let third = new ThirdType<string>()
...
// here result is of type ThirdType<int>
let result = ThirdType.DoWork third (fun x -> x.Length())
问题:
需要实现一个名为Do的函数,它接受两个参数,第一个是一个对象,类型可以是FirstType<'a>、SecondType<'a>或ThirdType<'a>中的一种,第二个是一个类型为('a -> 'b)的函数,其中'b'可以是'a'之外的另一种类型。所以,这个函数应该确定它的第一个输入参数的类型,并基于此返回适当的类型。
Do函数的返回类型:
- 如果Do函数的第一个参数的类型是FirstType<'a>,则返回类型应该是FirstType<'b>的对象
- 如果Do函数的第一个参数的类型是SecondType<'a>,则返回类型应该是SecondType<'b>的对象
- 如果Do函数的第一个参数的类型是ThirdType<'a>,则返回类型应该是ThirdType<'b>的对象
期望的,这些类的使用示例:
let first = new FirstType<int>()
let second = new SecondType<int>()
let third = new ThirdType<string>()
...
// here result1 should be of type FirstType<string>
let result1 = Do first (fun x -> "hello" + x.toString())
// here result2 should be of type SecondType<bool>
let result2 = Do second (fun x -> 2 = 4)
// here result3 should be of type ThirdType<int>
let result3 = Do third (fun x -> x.Length())
我曾考虑过函数重载,但在F#中不允许使用。现在我在思考如何使函数返回真正不同的类型,而不是辨别联合类型,因为在调用函数时它期望一个特定的类型。
更新:我已经看了John Palmer的评论并尝试了它。
type Ops =
static member Do (f: 'a -> 'b) (x:FirstType<'a>) = ...
static member Do (f: 'a -> 'b) (x:SecondType<'a>) = ...
static member Do (f: 'a -> 'b) (x:ThirdType<'a>) = ...
尝试创建函数时:
let Do f x = Ops.Do f x
出现以下错误:
错误:此方法的一个或多个重载已使用柯里化参数。请考虑重新设计这些成员,以采用元组形式的参数。
尝试将此 Do 函数作为Ops类的成员使用时会出现相同的错误:
let result1 = first |> Ops.Do(fun x -> x + 2)
let result2 = second |> Ops.Do(fun x -> "hello" + x.ToString())
let result3 = third |> Ops.Do(fun x -> x = 1) sq
重新设计具有元组形式参数的Ops类型中的Do方法,并创建如下的Do函数时:
let Do f x = Ops.Do (f, x)
在错误列表中出现以下错误:
错误:在此程序点之前,无法根据类型信息确定方法'Do'的唯一重载。可能需要类型注释。候选项:静态成员Ops.Do:f:('a ->'b)* x:FirstType<'a> -> FirstType<'b>,静态成员Ops.Do:f:('a ->'b)* x:SecondType<'a> -> SecondType<'b>,静态成员Ops.Do:f:('a ->'b)* x:ThirdType<'a> -> ThirdType<'b>
因此,我只能使用指定类名(Ops)和元组形式来使用Do.. 我已经通过错误消息理解了这一点。
有没有办法使用重载的成员方法进行柯里化?
我想要的用法是这样的:
let result = input |> Do someFunction
如果有人有任何想法或建议,我会很高兴。也许我在某些方面是错误的。