Replace the value of one item of single case discriminated union? - f#

See I have a single case discriminated union
type R = R of string * int * sting option * .....
And I got a value of R.
let r: R = getAValue ()
Now I need to replace the first item of r to an empty string and keep all other value. How to do it? Record type has the with construct
let r' = { r with Item1 = "" }
I know it can use 'pattern match' to extract all the items and create a new one. But it seems very cumbersome.

I assume you do not want to involve reflection, do you?
Then, I believe your only option would be using pattern matching. The (quite limited) burden would be defining the r-ity of your type Ras a pattern for matching.
Let's assume, for example, that your R wraps a tuple of 3 elements, i.e. has r-ity 3:
type R = R of string * int * string option
In this case all you need is to do define the following function:
let modR = function
| R(x,y,z) -> R("",y,z)
The signature of modR is R -> R, a quick check of your scenario:
let r = R("abc",1,None)
modR r
in fsi brings back
>
val it : R = R ("",1,None)
All you would need for applying the above to your specific R is set the actual r-ity of your type into the pattern.
UPDATE: As Fyodor Soikin pointed, a matching function isn't needed at all for unwrapping a single-case DU (see the docs). The sought convertion function definition may be defined as simple as
let modR (R(_,y,z)) = R("",y,z)
UPDATE2: While considering the comment from ca9163d9 I recalled just another flavor of pattern matching, namely as Pattern. Using it while implementing the sought conversion in the form of DU member gives:
type R = R of string * int * string option with
member self.modR() = let R(_,b,c) as x = self in R("",b,c)
Also #FyodorSoikin and #kaefer have pointed out in the comments that as x form isn't required for the simple DU unwrapping, similarly to terser modR function definition above:
member self.modR() = let (R(_,b,c)) = self in R("",b,c)

Related

Extending records with additional fields

I have a data pipeline where at each step more data fields are required. I would like to do this in a functional way by respecting immutability. I could achieve this with a class by I am wondering if there is an F# way of doing it?
// code that loads initial field information and returns record A
type recordA = {
A: int
}
// code that loads additional field information and returns record AB
type recordAB = {
A: int
B: int
}
// code that loads additional field information and returns record ABC
type recordABC = {
A: int
B: int
C: int
}
As records are sealed I can't just inherit them. How can I avoid having to define a new record with the exact same fields as the previous step and adding the required fields? Preferably I would like to have something like one record that has all required fields and the fields get assigned to their values in each step.
Note that the number of fields added in each step could be more than 1.
I think this can be a good use case for the anonymous records recently introduced in F#.
let a = {| X = 3 |}
let b = {| a with Y = "1"; Z = 4.0|}
let c = {| b with W = 1 |}
printfn "%d, %s, %f, %d" c.X c.Y c.Z c.W
One way to do it in a very FP-style would be to use a DU with a case for each step of the workflow, and the appropriate data for each step in each case:
type WorfklowState =
| StepOne of int
| StepTwo of int * int
| StepThree of int * int * int
Then your entire workflow state, both what step you're currently on and the data produced/consumed by that step, would be modeled in the data type. Of course, you would probably create record types for the data of each case, rather than using progressively larger tuples.
Depending on the application, this may be a (mis-)use case for a dynamic data container.
F# might help by providing user-defined dynamic lookup operators, for which a special syntactic translation occurs.
let (?) (m : Map<_,_>) k = m.Item k
// val ( ? ) : m:Map<'a,'b> -> k:'a -> 'b when 'a : comparison
let (?<-) (m : Map<_,_>) k v = m.Add(k, v)
// val ( ?<- ) : m:Map<'a,'b> -> k:'a -> v:'b -> Map<'a,'b> when 'a : comparison
let m = Map.empty<_,_>
let ma = m?A <- "0"
let mabc = (ma?B <- "1")?C <- "2"
ma?A // val it : string = "0"
mabc?C // val it : string = "2"
You can "inherit" records:
type RecordA =
{
a : int
}
type RecordAB =
{
a : RecordA
b : int
}
type RecordABC =
{
ab : RecordAB
c : int
}
Then you can access all of the elements, though with longer and longer chain as you go deeper and deeper.
However, why don't you just use a list of elements to store the result?
First, I would create a type to handle all possible types that you may have on each step, e.g.:
type Step =
| Int of int
| String of string
// ...
Then you can represent the workflow simply as:
type WorkflowState = list<Step>
and if you want to ensure that you always have at least one element then you can use:
type WorkflowState = Step * list<Step>
However, the records have labels and the structure above does not have them! So, if you do need labels, then you can represent them by a map using either a strong type:
type Label =
| A
| B
// ...
type WorkflowMappedState = Map<Label, Step>
or just a string based one, e.g.
type WorkflowMappedState = Map<string, Step>
The benefits of list or map based approach in comparison to the answers above is that you don't have to know the maximum number of possible steps. What if the number of steps is over 100? Would you want to create a record with 100+ labels? Most likely not! The anonymous records are great, but what if you want to use them outside of module where they were created? I think that that would cause some troubles.
Having said all that, I think that I would go with a list based approach: type WorkflowState = list<Step>. It is very F# way and it is very easy to transform further.

Unwrap F# single-case discriminated union tuple type

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?
In your case, you can write:
type Composite = Composite of int * string
let unwrap (Composite (a, b)) = a, b
which corresponds to:
let unwrap x =
match x with
| Composite (a, b) -> a, b
What's happening here is that F# allows you to deconstruct function arguments inline using arbitrarily complex pattern matching. This is often mentioned when introducing single case DU's, but it's rarely followed to the conclusion, which leads people to believe single case DU's are somehow special that way.
In fact, you can use it when you have multiple cases (as long as each case binds the same set of variables):
type Composite = Composite of int * string | JustString of string
let unwrapString (Composite (_, s) | JustString s) = s
But most of the time, you'd pattern match on simpler types, like tuples:
let f (a, b, c) = ...
or even more curiously:
let f () = ...
Here () is a pattern match on the lone value of unit type - rather than some kind of "visual marker for a parameterless function", as it's often described.
You defined the type as a single-case discriminated union with named fields:
type Composite = Composite of integer:int * someStr:string
When defined in this way, the fields of the union case are not a simple tuple. They get treated in a special way and, for example, the names are used as property names in compiled code. The pattern matching does not automatically turn the elements into a tuple and so you have to unwrap them separately:
let unwrap (Composite(i, s)) = i, s
However, you can also define single-case union where the field is an ordinary tuple. (Note that you need the parentheses around the tuple type - otherwise, it also ends up being treated in a special way, except that the items will be compiled as Item1 and Item2.)
type Composite = Composite of (int * string)
With this definition, your unwrap function will work fine and extract the tuple value:
let unwrap (Composite c) = c
You can also use a nested pattern to get the number and the string like in the previous case:
let unwrap (Composite(i, s)) = i, s
The fact that this behaves differently depending on whether you write A of (T1 * T2) or whether you write A of T1 * T2 is a bit subtle - the two probably need to be distinguished just so that the compiler knows whether to compile the fields as two separate fields or as one field of type System.Tuple<T1, T2>. I cannot quite imagine any other case where the difference would matter.
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

Constructing and deconstructing records

The msdn page documenting Records (F#) details record expressions for record construction and record patterns for deconstruction, the latter without naming them as such.
Here's an example which uses both techniques for an arithmetic operator:
// Simple two-dimensional generic vector defintion
type 'a UV =
{ U : 'a; V : 'a }
static member inline (+) ({ U = au; V = av }, { U = bu; V = bv }) =
{ U = au + bu; V = av + bv }
This appears unwieldy and not very readable. For deconstruction, there are dot-notation or functions as alternatives. Since the dot-notation operator has a special dispensation in section 8.4.2 Name Resolution and Record Field Labels of the spec (an expression’s type may be inferred from a record label), there's normally no need to annotate. Accessor functions like let u { U = u } = u wouldn't give us any advantages then.
For construction, I think a case can be made for a function as record constructor. Access to the original constructor might even be restricted:
type 'a UV =
internal { U : 'a; V : 'a }
let uv u v = { U = u; V = v }
type 'a UV with
static member inline (+) (a, b) =
uv (a.U + b.U) (a.V + b.V)
Is this an idiomatic thing to do? How to package such functions in modules and handle namespace issues?
Short answer: I don't think there is a general convention here at the moment so it will be a personal decision in the end.
To summarise what you get for free with records in F# is:
Construct: { U = u; V = v } (bracket-notation)
Deconstruct: let u = record.u (dot-notation) and let {U = u} = record (pattern matching)
Update: {record with U = u} (bracket-notation)
But you don't get first class functions for free, if you want you can code them by hand.
The following is what I would personally use as convention:
A static member New with curried arguments for record construction.
For update and deconstruction I would use some kind of Lenses abstraction.
Here's an example of the code I would have to add by hand:
// Somewhere as a top level definition or in a base library
type Lens<'T,'U> = {Get: 'T -> 'U; Set: 'U -> 'T -> 'T } with
member l.Update f a = l.Set (f (l.Get a)) a
type UV<'a> = {U : 'a; V : 'a } with
// add these static members to your records
static member New u v : UV<'a> = {U = u; V = v}
static member u = {Get = (fun (x: UV<'a>) -> x.U); Set = fun t x -> {x with U = t}}
static member v = {Get = (fun (x: UV<'a>) -> x.V); Set = fun t x -> {x with V = t}}
let uvRecord = UV.New 10 20
let u = UV.u.Get uvRecord
let uvRecord1 = UV.u.Set (u+1) uvRecord
let uvRecord2 = UV.u.Update ((+)1) uvRecord
This way I would have first class functions for construction, deconstruction but also for updates plus other very interesting Lenses properties as you can read in this post.
UPDATE (in response to your comments)
Of course they can be defined later, what does it change?
The same applies for the New constructor, it can be defined later but that's actually a good thing.
The accessor functions you defined can also be defined later, indeed any first-class getter, setter or updater value can be defined later.
Anyway the answer to your question is "no, there are no conventions" the rest it's a personal decision, which would be my decision and also many Haskellers are pushing to get some kind of automatic Lenses for Haskell records.
Why would I decide to go this way? Because in terms of lines of code the effort of adding a simple accessor function is almost the same as adding a get-Lens, so for the same price I get more functionality.
If you are not happy with the Lenses discussion please tell me, I can delete it and leave the short answer, or I can delete the whole answer too if it's confusing instead of clarifying.
Or may be I misunderstood your question, for me your question was about which convention is generally used to add first-class constructors, getters and setters values for records.
Composition is not the only advantage of Lenses, you can do many things, keep reading about them, they provide a very interesting abstraction and not only restricted to records.

Names bound to both the decomposed discriminated union components AND an original composed value

I can't find documentation on this. I need to decompose a Discriminated Union value into some of its components but I also need to use the item as a whole within the body of a function as well.
I can do let matcher = function MyDU(_,b,_) -> b or let extractor MyDU(_,b,_) = b but what if I also need the reference to the MyDU value for something like ... -> RedundantWrapper(myDU, b)
I've tried:
let extractor myDU =
let MyDU(_,b,_) = myDU
RedundantWrapper(myDU, b)
but I don't think that is the right syntax. Perhaps I can do this some longer way, but it seems like there would be a short way.
Thanks!
Like this:
let (Some(x) as o) = Some 1
// val o : int option = Some 1
// val x : int = 1
Also, I just realized that this short-hand is allowed which I think everyone here will agree is PRETTY AWESOME.
let extractor (myDU & MyDU(_,b,_)) =
RedundantWrapper(myDU, b)

F# Implement list [] operator on a class?

I have a custom class in F# and I want to implement the [] list operator such that
let myClass = new myClassObj()
let someVal = myClass.[2]
I can't seem to find this on the web - I probably don't know the right term to search for... thanks in advance
You just need to implement an Item indexed property. E.g.
type MyClass() =
member x.Item with get(i:int) = (* some logic involving i here *)
If you start at the F# language reference, and go to members, one of the topics is indexed properties.
It is worth adding that F# also supports slicing syntax (which isn't mentioned on the indexed properites MSDN page). It means that you can index not only a single element such as m.[0] but also a slice such as m.[0..5] or an unbounded range m.[5..]. This is quite useful for various numerical data types (such as matrices).
To support this feature, the type must define GetSlice method. The following example demonstrates this using a 2D scenario:
type Foo() =
member x.GetSlice(start1, finish1, start2, finish2) =
let s1, f1 = defaultArg start1 0, defaultArg finish1 0
let s2, f2 = defaultArg start2 0, defaultArg finish2 0
sprintf "%A, %A -> %A, %A" s1 s2 f1 f2
> let f = new Foo()
f.[1.., 1..10];;
val it : string = "1, 1 -> 0, 10"
The arguments are of type int option and here we use defaultArg to specify 0 as the default value.

Resources