我有一个函数,它接受一个类型为object的参数,并需要将其向下转换为一个option<obj>。
member s.Bind(x : obj, rest) =
let x = x :?> Option<obj>如果我将一个'Microsoft.FSharp.Core.FSharpOption'1System.String‘类型的对象作为x传递(例如),那么最后一行将抛出异常:无法将类型为Option<string>的对象转换为'Microsoft.FSharp.Core.FSharpOption'1System.Object'.类型。
或者,如果我尝试类型测试:
member s.Bind(x : obj, rest) =
match x with
| :? option<obj> as x1 -> ... // Do stuff with x1
| _ -> failwith "Invalid type"那么x就永远无法与option<obj>相匹配。
为了使此工作正常进行,我目前必须指定选项包含的类型(例如,如果函数被传递为option<string>,并且我将参数向下转换为该类型,而不是option<obj>,则该函数可以工作。
是否有一种方法可以将参数降为option<obj>而不指定该选项包含的类型?我尝试过option<_>、option<#obj>和option<'a>,结果都是一样的。
作为背景,参数需要类型为obj,因为我正在为monad编写接口,因此Bind需要绑定不同类型的值,具体取决于实现接口的monad。这个特定的monad是一个延续monad,所以它只想确保参数是Some(x)而不是None,然后将x传递给rest。(我需要这个接口的原因是我正在编写一个monad转换器,我需要一种方法来告诉它它的参数monad实现绑定和返回。)
更新:在选项成为该函数的参数之前,通过向上转换该选项的内容来解决这个问题,但我仍然很想知道是否可以将一个对象(或泛型参数)键入或强制转换到一个选项中,而不必担心该选项包含什么样的类型(当然,该转换是有效的,也就是说,该对象实际上是一个选项)。
发布于 2011-06-09 09:43:59
目前还没有解决这个问题的好办法。
问题是您需要在模式匹配中引入一个新的泛型类型参数(当与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这将为您提供包含任意选项类型的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))发布于 2011-06-09 08:22:57
我不知道为什么您需要将输入作为obj,但是如果您的输入是Option<_>,那么很容易:
member t.Bind (x : 'a option, rest : obj option -> 'b) =
let x = // val x : obj option
x
|> Option.bind (box >> Some)
rest x发布于 2011-06-09 19:42:04
要回答最后一个问题:如果您需要一种通用的方法来检查选项,而事先不使用装箱值,则可以使用Tomas代码的一些细微变化:
let (|Option|_|) value =
if obj.ReferenceEquals(value, null) then None
else
let typ = value.GetType()
if typ.IsGenericType && typ.GetGenericTypeDefinition() = typedefof<option<_>> then
let opt : option<_> = (box >> unbox) value
Some opt.Value
else None
//val ( |Option|_| ) : 'a -> 'b option
let getValue = function
| Option x -> x
| _ -> failwith "Not an option"
let a1 : int = getValue (Some 42)
let a2 : string = getValue (Some "foo")
let a3 : string = getValue (Some 42) //InvalidCastException
let a4 : int = getValue 42 //Failure("Not an option")https://stackoverflow.com/questions/6289761
复制相似问题