Generic extraction from a constructor
In F# and 开发者_StackOverflow中文版OCaml I wind up writing a lot of code like
type C = Blah of Whatever  
let d = Blah (createWhatever ())  // so d is type C  
...  
let x = match d with | Blah b -> b
What I'd like is this
...  
let x = peel d
Where peel would work for any constructor/discriminator.
Surely I'm not the only one annoyed by this. edit: Good answers, but I don't have the rep to vote on them. How about this situation?member self.Length = match self with | L lab -> lab.Length
It is not possible to do that safely : if peel was a function, what would be its type ? It cannot be typed and therefore cannot be a "good guy" in the language.
You may :
- use reflection (in F#) or type-breaking functions (in OCaml it's the - Objmodule), but you will get something unsafe with an imprecise type, so it's rather ugly and "use at your own risk"
- use metaprogramming to generate different versions of - peelat each type for you. For example, using the type-conv OCaml tool, you may have- type blah = Blah of somethingdefine a function- peel_blahimplicitly, and- type foo = Foo of somethingdefine- peel_foo.
The better solution imho is... not to need such a peel in the first place. I see two possibilities:
- You may use clever patterns instead of a function : by using - let (Blah whatever) = f x, or- fun (Blah whatever) -> ..., you don't need an unpacking function anymore.
- Or you may, instead of writing - type blah = Blah of what, write- type blah = (blah_tag * whatever) and blah_tag = Blah- This way, you don't have a sum type but a product type (you write - (Blah, whatever)), and your- peelis just- snd. You still have a different (incompatible) type for each- blah,- fooetc, but a uniform access interface.
As mentioned, the let is convenient to do a pattern matching.
If you want to access the value in the middle of an expression, where patterns are not allowed, I suggest adding a member to the types:
type C = Blah of int
with member c.Value = match c with Blah x -> x
let x = Blah 5
let y = Blah 2
let sum = x.Value + y.Value
I would write this instead:
type C = Blah of Whatever  
let d = Blah (createWhatever ())  // so d is type C  
...
let (Blah x) = d
For your second situation, I like Laurent's member x.Value = match x with Blah v -> v.
Works for DUs...will need tweaking to work with class constructors:
open Microsoft.FSharp.Reflection
let peel d = 
    if obj.ReferenceEquals(d, null) then nullArg "d"
    let ty = d.GetType()
    if FSharpType.IsUnion(ty) then
        match FSharpValue.GetUnionFields(d, ty) with
        | _, [| value |] -> unbox value
        | _ -> failwith "more than one field"
    else failwith "not a union type"
By the way: I wouldn't typically do something like this, but since you asked...
 
         加载中,请稍侯......
 加载中,请稍侯......
      
精彩评论