泛型F#函数:如何获取F#歧视联盟的类型? [英] Generic F# function: How to get the Type of an F# Discriminated Union?

查看:92
本文介绍了泛型F#函数:如何获取F#歧视联盟的类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

代码示例: http://www.tryfsharp.org/create/dutts/Generics .fsx



我的F#中有一些映射代码,它接受一个C#对象并将它包装在一个有区别的联合中。

  module MyModule = 
type MappedThings =
| DoThings of External.Things.DoThings

type MappedStuff =
| DoStuff of External.Stuff.DoStuff

由于我总是在我的区分联合中使用与外部相同的名称对象我想尝试使我的映射代码具有通用的可伸缩性。这是我迄今为止所尝试的:

  let toDomain< T> external:'T = 
let found = FSharpType.GetUnionCases(typeof< T>)|> Seq.where(fun t - > t.Name = external.GetType()。Name)|> Seq.head
FSharpValue.MakeUnion(找到,[| box external |]):?> 'T

我试图像这样使用它:

  let testThings = toDomain< MyModule.MappedThings> doExternalThings 
let testStuff = toDomain< MyModule.MappedStuff> doExternalStuff

这对第一次调用来说很好,但是如果我尝试将它用于MyModule.MappedStuff类型它抱怨

 这个表达式应该有DoThings类型,但是这里有类型DoStuff 

我试过使用静态解析的类型参数,^ T,但是输入< ^ T>抱怨。



我想我可以得到这个工作,如果我能以某种方式通过类型(如果这是正确的术语,例如MyModule.Mapped)作为参数,但我不知道如何以编程方式。

任何人都可以帮忙吗?

解决方案

您为> Makeunion 的第二个参数引入的装箱会将类型推断抛出轨道,事实上,函数不再是通用的。注释参数或移除

  let toDomain< T> external:'T = 
let found = FSharpType.GetUnionCases(typeof< T>)|> Array.find(fun t - > t.Name = external.GetType()。Name)
FSharpValue.MakeUnion(found,[| external |]):?> 'T


Code example: http://www.tryfsharp.org/create/dutts/Generics.fsx

I have some mapping code in my F# which takes a C# object and wraps it in a discriminated union.

module MyModule =
    type MappedThings =
        | DoThings of External.Things.DoThings

    type MappedStuff =
        | DoStuff of External.Stuff.DoStuff

As I always use the same name in my discriminated union as the external object I would like to try to make my mapping code generic for scalability. This is what I've tried so far:

let toDomain<'T> external : 'T =
    let found = FSharpType.GetUnionCases(typeof<'T>) |> Seq.where (fun t -> t.Name = external.GetType().Name) |> Seq.head
    FSharpValue.MakeUnion(found, [| box external |]) :?> 'T  

I am trying to use it like this:

let testThings = toDomain<MyModule.MappedThings> doExternalThings
let testStuff = toDomain<MyModule.MappedStuff> doExternalStuff 

This works fine for the first call, but if I try to use it for MyModule.MappedStuff type it complains with

This expression was expected to have type DoThings but here has type DoStuff

I've tried using statically resolved type parameters, ^T, but the typeof<^T> complains.

I was thinking I could get this to work if I could somehow pass the "Type" (if that's the correct term, e.g. MyModule.Mapped) as a parameter but I don't know how to get that programmatically.

Can anyone help?

解决方案

I think that the additional boxing that you introduce for the 2nd parameter of Makeunion throws the type inference off the track and in fact, the function isn't generic anymore. Either annotate the argument or remove the box.

let toDomain<'T> external : 'T =
    let found = FSharpType.GetUnionCases(typeof<'T>) |> Array.find (fun t -> t.Name = external.GetType().Name) 
    FSharpValue.MakeUnion(found, [| external |]) :?> 'T 

这篇关于泛型F#函数:如何获取F#歧视联盟的类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆