We can unwrap type like type Address = Address of string
using unwrapping function like
let unwrapAddress (Address a) = a
let addr = Address "sdf"
let str = unwrapAddress addr
so str
will be of type string
, but if there is type like this approach willn't work:
type Composite = Composite of integer:int * someStr:string
let unwrap (Composite c) = c
will produce error
let unwrap (Composite c) = c;;
------------^^^^^^^^^^^
error FS0019: This constructor is applied to 1 argument(s) but expects 2
Can I somehow unwrap composite types to a simple tuple?
These all work for me. It's your matching syntax, that most often you'll find used with match statements, but it's on the l.h.s. of an assignment. Possibly, this makes the most sense, initially, for tuples, but you can use this with any structure.
let (a,b) = (1,2)
let (x,_) = (4,5)
Two other interesting things to try:
let (head::tail) = [1;2;3;4]
FSI responds warning FS0025: Incomplete pattern matches on this expression. For example, the value '[]' may indicate a case not covered by the pattern(s).
"That's true," you reason aloud. "I should express it as a match and include an empty list as a possibility". It's better to bubble these kinds of warnings into fully bonafide errors (see: warn as error e.g. --warnaserror+:25). Don't ignore them. Resolve them through habit or the compiler enforced method. There's zero ambiguity for the single case, so code-on.
More useful + interesting is the match syntax on the l.h.s. of a function assignment. This is pretty cool. For pithy functions, you can unpack the stuff inside, and then do an operation on the internals in one step.
let f (Composite(x,y)) = sprintf "Composite(%i,%s)" x y
f (Composite(1,"one"))
> val it : string = "Composite(1,one)"
About your code:
type Address = Address of string //using unwrapping function like
let unwrapAddress (Address a) = a
let addr = Address "sdf"
let str = unwrapAddress addr
type Composite = Composite of integer:int * someStr:string
let unwrap (Composite(c,_)) = c
let cval = Composite(1,"blah")
unwrap cval
Workaround:
let xy = Composite(1,"abc") |> function (Composite(x,y))->(x,y)
... but the nicer way, assuming you want to keep the named elements of your single case DU would be...
let (|Composite|) = function | Composite(x,y)->(x,y)
let unwrap (Composite(x)) = x
let unwrap2 (Composite(x,y)) = (x,y)
... not strictly decomposing through a single case DU, but decomposing through a single-case Active Pattern
lastly, you could attach a method to the Composite structure...
module Composite =
let unwrap = function | Composite(x,y)->(x,y)
One of the best discussions about using this technique is over here
Also, check out the signature that unwrap gives us: a function that takes a Composite (in italics), and returns an int (in bold)
Signature -- val unwrap : Composite -> int