假设有一个用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。
目前。这些类的示例用法:
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&lt;'a&gt;的对象。或者到SecondType&lt;'a&gt;或者对于ThirdType&lt;'a&gt;,second - 类型的函数('a - &gt;'b),其中'b可以是来自'a的另一种类型。所以,这个函数应该确定它的第一个输入参数的类型并基于此 - 返回适当的类型。
执行功能的返回类型:
所需。这些类的示例用法:
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#中使用它。我现在正在考虑如何使函数返回真正不同的类型,而不是Discriminated Unions,因为在调用函数时它需要特定的类型。
更新
我查看了约翰帕尔默的评论并试了一下。
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
出现以下错误:
错误:此方法的一个或多个重载具有curried参数。考虑重新设计这些成员以采用tupled形式的参数。
尝试将此执行函数用作类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
当使用tupled形式的参数重新设计Ops类型的Do方法并创建像这样的Do函数时:
let Do f x = Ops.Do (f, x)
..错误列表中出现以下错误:
错误:无法根据此程序点之前的类型信息确定方法“Do”的唯一重载。可能需要类型注释。候选人:静态成员Ops.Do:f :('a - &gt;'b)* x:FirstType&lt;'a&gt; - &GT; FirstType&lt;'b&gt;,静态成员Ops.Do:f :('a - &gt;'b)* x:SecondType&lt;'a&gt; - &GT; SecondType&lt;'b&gt;,静态成员Ops.Do:f :('a - &gt;'b)* x:ThirdType&lt;'a&gt; - &GT; ThirdType&LT;'B个
所以,我只能使用执行指示一个类名(Ops)和一个tupled形式..正如我在错误消息的帮助下所理解的那样。
有没有办法在重载的成员方法中使用currying?
我梦寐以求的用法是这样的:
let result = input |> Do someFunction
如果有人有任何想法或建议,我会很高兴。也许我错了。
答案 0 :(得分:2)
我认为这就是你要做的事情:
type FirstType<'a> = FirstType of 'a
type SecondType<'a> = SecondType of 'a
type ThirdType<'a> = ThirdType of 'a
type Ops = Ops with
static member ($) (Ops, FirstType a) = fun f -> FirstType (f a)
static member ($) (Ops, SecondType a) = fun f -> SecondType (f a)
static member ($) (Ops, ThirdType a) = fun f -> ThirdType (f a)
let inline Do f x = (Ops $ f) x
let first = FirstType 10
let second = SecondType 12
let third = ThirdType "Hello"
let result1 = Do first (fun x -> "hello" + x.ToString())
let result2 = Do second (fun x -> 2 = 4)
let result3 = Do third (fun x -> x.Length)
在these posts中查找有关内联和重载的详细信息。您似乎正在尝试在包装类上实现通用映射函数,这与Functor Typeclass in Haskell相对应,{{3}}具有函数fmap
,与Do
函数具有相同的签名,但与论点翻了。