如何使函数在fsharp中返回真正不同的类型? [英] How to make a function to return really different types in fsharp?
问题描述
假定有一个用FSharp编写的第三方库,它包含几个通用类,例如:
Assume that there is a third-party library written in FSharp, it contains several generic classes, for example as follows:
-
类型 FirstType<'a>
具有方法 DoWork ,该方法接受:
has method DoWork, that accepts:
-
类型为 FirstType<'a> ,
第二个参数是类型('a->'b)
second param is a function of type ('a -> 'b)
DoWork 方法的返回类型为 FirstType<'b>
类型 SecondType<'a>
具有方法 DoWork ,该方法接受:
has method DoWork, that accepts:
-
类型为 SecondType<'a> ,
第二个参数是类型('a->'b)
second param is a function of type ('a -> 'b)
DoWork 方法的返回类型为 SecondType<'b>
类型 ThirdType <'a>
具有方法 DoWork ,该方法接受:
has method DoWork, that accepts:
-
类型为 ThirdType <'a>,
第二个参数是类型('a->'b)
second param is a function of type ('a -> 'b)
DoWork 方法的返回类型为 ThirdType<'b>
这些类没有公共接口或父类,类型Object是它们的唯一公共父类.
These classes have no common interfaces or parent classes, type Object is their only common parent.
以下每种类型都有一个名为 DoWork 的方法.它接受两个参数:
Each of the types below has one method named DoWork. It accepts two parameters:
- 第一个具有包含DoWork方法的类的类型
- 第二个是一个函数(它接受类型等于该类的泛型参数的参数,并返回任何类型的元素,称其为'b)
然后,此DoWork函数应返回对象,该对象具有其所在类的类型,但泛型类型参数等于'b.
Then this DoWork function should return the object which has type of the class it is situated in, but with generic type parameter equal to '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以外的类型.因此,此函数应确定其第一个输入参数的类型并基于此-返回适当的类型.
It is required to implement a function called Do, that accepts two parameters, first - an object that has type either equal to FirstType<'a> or to SecondType<'a> or to ThirdType<'a>, second - a function of type ('a -> 'b) where 'b can be a type another from 'a. So, this function should determine the type of it's first input parameter and based on this - return appropriate type.
执行函数的返回类型:
-
如果Do函数的第一个参数的类型为FirstType<'a> ,则
- 应该是类型FirstType<'b>的对象. 如果Do函数的第一个参数的类型为SecondType ,则
- 应该是类型为SecondType<'b>的对象. 如果Do函数的第一个参数的类型为ThirdType<'a> ,则
- 应该是类型为ThirdType<'b>的对象.
- should be an object of type FirstType<'b> if the first param of Do function was of type FirstType<'a>
- should be an object of type SecondType<'b> if the first param of Do function was of type SecondType<'a>
- should be an object of type ThirdType<'b> if the first param of Do function was of type ThirdType<'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#中使用它.我现在正在考虑如何使一个函数返回真正不同的类型,而不是歧视联盟,因为在调用该函数时,它期望一个特定的类型.
I have thought of function overloading, but it is not allowed to be used in F#. I am now thinking of how to make a function return really different types, not Discriminated Unions, because at the point of calling the function it expects a specific type.
更新:
我查看了约翰·帕尔默(John Palmer)的评论,并尝试了它.
I have looked at the comment of John Palmer and tried it.
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
出现以下错误:
错误:此方法的一个或多个重载具有可管理的参数.考虑重新设计这些成员以采用元组形式的参数.
Error: One or more of the overloads of this method has curried arguments. Consider redesigning these members to take arguments in tupled form.
当尝试将此 Do 函数用作Ops类的成员时,存在相同的错误:
The same error is when trying to use this Do function as a member of class 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函数时:
When redesigning Do methods in Ops type with arguments in tupled form and creating Do function like this:
let Do f x = Ops.Do (f, x)
..错误列表中有以下错误:
.. there is the following error in the Error List:
错误:无法根据此程序点之前的类型信息来确定方法'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>
Error: A unique overload for method 'Do' could not be determined based on type information prior to this program point. A type annotation may be needed. Candidates: static member Ops.Do: f:('a -> 'b) * x:FirstType<'a> -> FirstType<'b>, static member Ops.Do: f:('a -> 'b) * x:SecondType<'a> -> SecondType<'b>, static member Ops.Do : f:('a -> 'b) * x:ThirdType<'a> -> ThirdType<'b>
因此,我只能在指示类名(Ops)和元组形式的情况下使用 Do .据我在错误消息的帮助下可以理解.
So, I am able to use Do only with indicating a class name (Ops) and in a tupled form.. as I have understood with the help of error messages.
有什么方法可以使用带有超载成员方法的curring?
我梦of以求的用法是这样的:
The usage I am dreaming of is like this:
let result = input |> Do someFunction
如果有人有任何想法或建议,我会很高兴.也许在某些时候我错了.
I would be happy if someone has any ideas or suggestions. Maybe I am wrong at some point.
推荐答案
我认为这是您要尝试做的事情:
I think this is what you are trying to do:
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)
在这些帖子中找到有关内联和重载的更多信息.看来您正在尝试在包装类上实现通用映射函数,这对应于 Haskell中的Functor Typeclass ,具有函数fmap
,其签名与Do
函数相同,但参数已翻转.
Find more about inline and overloading in these posts. It seems you are trying to implement a generic map function over your wrapper classes, this correspond to the Functor Typeclass in Haskell, which has a function fmap
, with the same signature as your Do
function but with the arguments flipped.
这篇关于如何使函数在fsharp中返回真正不同的类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!