我有一个函数,它接受一个object类型的参数,需要将它向下转换为option<obj>.
member s.Bind(x : obj, rest) =
let x = x :?> Option<obj>
Run Code Online (Sandbox Code Playgroud)
如果我传递(例如)Option<string>as x,则最后一行抛出异常:无法转换类型为"Microsoft.FSharp.Core.FSharpOption'1 [System.String]"的对象以键入"Microsoft.FSharp.Core.FSharpOption" 1 [System.Object的]".
或者,如果我尝试进行类型测试:
member s.Bind(x : obj, rest) =
match x with
| :? option<obj> as x1 -> ... // Do stuff with x1
| _ -> failwith "Invalid type"
Run Code Online (Sandbox Code Playgroud)
然后x从不匹配option<obj>.
为了使这项工作,我当前必须指定选项包含的类型(例如,如果函数被传递option<string>,并且我将参数向下转换为而不是option<obj>,函数可以工作.
有没有一种方法可以将参数向下转换为option<obj>不指定选项包含的类型?我试过了option<_>,option<#obj>并且option<'a>得到了相同的结果.
作为背景,参数需要是类型的,obj因为我正在为monad编写接口,因此Bind需要根据实现接口的monad绑定不同类型的值.这个特殊的monad是一个延续monad,所以它只是想确定参数是否Some(x)存在None,然后传递x给休息.(我需要接口的原因是因为我正在编写一个monad转换器,我需要一种方法告诉它它的参数monad实现bind和return.)
更新:我成功通过向上转换选项的内容,然后它成为此函数的参数,但我仍然很想知道我是否可以对选项进行类型测试或转换对象(或通用参数)不必担心选项包含的类型(当然假设转换是有效的,即对象确实是一个选项).
目前没有任何好办法解决这个问题.
问题是你需要在模式匹配中引入一个新的泛型类型参数(当匹配时option<'a>),但F#只允许你在函数声明中定义泛型类型参数.所以,你唯一的解决方案是使用一些反射技巧.例如,您可以定义隐藏此的活动模式:
let (|SomeObj|_|) =
let ty = typedefof<option<_>>
fun (a:obj) ->
let aty = a.GetType()
let v = aty.GetProperty("Value")
if aty.IsGenericType && aty.GetGenericTypeDefinition() = ty then
if a = null then None
else Some(v.GetValue(a, [| |]))
else None
Run Code Online (Sandbox Code Playgroud)
这将为您提供None或Some包含obj任何选项类型:
let bind (x : obj) rest =
match x with
| SomeObj(x1) -> rest x1
| _ -> failwith "Invalid type"
bind(Some 1) (fun n -> 10 * (n :?> int))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2182 次 |
| 最近记录: |