pipe record to object param list - f#

Given i have the type:
type NewsMessage(identifier:string, headline:string)
and this record:
type NewsMessageParams = {
identifier:string
headline:string
}
Is there an implicit way to adapt the record into the class constructor?
Something like so:
let newsMessageParmas = {identifier=""; headline=""}
new NewsMessage(newsMessageParams) //this is where i need help
You can do this with tuples using the ||> syntax. I would like to do this with a record.

Something like this would work:
let toClass {identifier = i; headline = h} = NewsMessage(i, h)
// Usage
let newsMessageParams = {identifier = ""; headline = ""}
let newsMessage = newsMessageParams |> toClass
Note that object constructor isn't first-class in F#, so you have more chances of using pipe operators if declaring NewsMessage as discriminated unions:
type NewsMessage = NewsMessage of string * string
let toTuple {identifier = i; headline = h} = i, h
let newsMessageParams = {identifier = ""; headline = ""}
let newsMessage = newsMessageParams |> toTuple |> NewsMessage

Related

DRY self-replicating type

Is there a succint way to express self-replicating types in F#? — That is, without repeating oneself.
// Manual self-replication
type Foo (par1 : Type1, par2 : Type2, par3 : Type3, par4 : Type4) =
let unique = new UniqueState() // unique for every instance of Foo
member this.SelfReplicate =
new Foo(par1, par2, par3, par4) // repeating myself
let a = new Foo(x, y, z, w)
let b = a.SelfReplicate
Attempt with manually injected self-replicator:
// Semi-automagic self-replication
type Foo' (par1 : Type1, par2 : Type2, par3 : Type3, par4 : Type4, replicate : unit -> Foo') =
let unique = new UniqueState() // unique for every instance of Foo'
member this.SelfReplicate = replicate() // not repeating myself
let rec foo' () = new Foo'(x, y, z, w, foo')
let a = foo'()
let b = a.SelfReplicate
I'm not sure how this can be any more succint without compiler magic. It just seems like there should be a way to capture the current arguments and type without repeating them syntactically.
You could define a type WithUnique<'T> which is a wrapper over a value of type 'T and adds a unique value to this. You may need to think about how you want the equality testing on those types to work - if you use record (as I do below), then two instances with different unique value will not be equal:
let rnd = System.Random()
let uniqueState() = rnd.Next()
type WithUnique<'T> =
{ Value : 'T; Unique : int }
static member Create(v) : WithUnique<'T> =
{ Value = v; Unique = uniqueState() }
member x.Replicate() =
{ Value = x.Value; Unique = uniqueState() }
The value of 'T is just one type, but this can be a tuple (or a record) if you need to wrap multiple things:
let wu1 = WithUnique.Create( (10, "hi") )
let wu2 = wu1.Replicate()
Given the above, wu1=wu2 will be false.

F# polymorphic function

Suppose I have 2 record types
type A = { a: string; parameters: parameter list }
type B = { b: string; parameters: parameter list }
where
type parameter = { name: string; value : string }
How can I write function parameter
let parameter name value entity =
{ entity with parameters = List.append
parameters
[ { name = name; value = value; } ]
}
Such as
let a = { a = "a", parameters = [] } |> parameter "p", "v" // a is a record of type A
let b = { b = "b", parameters = [] } |> parameter "p", "v" // b is record of type B
It is not idiomatic F#, but this can be done using SRTP. I assume you have simplified the use-case for StackOverflow, but if A and B are really not related types, then I think you should revisit your overall program design.
I defined a Parameter type as this:
type Parameter =
{
Name : string
Value : string
}
Now, we need to add a method to types A and B that implement the addition of a parameter:
type A =
{
A : string
Parameters : Parameter list
}
with
member this.AddParameter(p : Parameter) =
{
this with
Parameters =
p :: this.Parameters
}
And...
type B =
{
B : string
Parameters : Parameter list
}
with
member this.AddParameter(p : Parameter) =
{
this with
Parameters =
p :: this.Parameters
}
Then we can write an inline function that calls this method:
let inline addParameter (p : Parameter) (x : ^t) : ^t =
(^t : (member AddParameter : Parameter -> ^t) (x, p))
Here ^t will be replaced with A or B (or whatever) depending on the call-site. The syntax for SRTP isn't great, but it is better in F# 7.
Usage:
let p = { Name = "p"; Value = "abc" }
let a : A =
{ A = "a"; Parameters = [] }
|> addParameter p
printfn $"%A{a}"
let b : B =
{ B = "b"; Parameters = [] }
|> addParameter p
printfn $"%A{b}"

Is it possible to force record type in F# when doing an assignment?

To explain I think it is best with an example:
type myRec = {x: string}
type myRec2 = {x: string}
let x = {x = "hello"}
let y(a: myRec) = a.x
y(x);;
y(x);;
--^
error FS0001: This expression was expected to have type
myRec
but here has type
myRec2
So how do I force x to have the type myRec if both myRec and myRec2 has the same signature?
let x = { myRec.x = "hello" }
// or
let x:myRec = { x = "hello" }
// or
let x = { x = "hello" } : myRec
Further details and examples are available in the documentation.
EDIT: Incorporated alternatives from comments.
Yes you can:
let x = { new myRec() with x = "hello" }
use and to assign more fields:
let x = { new myRec3() with x = "hello" and y = "bye" }

how does the compiler treat extending a record

Does the compiler create a new location in memory when a record is extended (deep copy?) or does the compiler make the record mutable and modify the value?
For example:
type MyRecord = { A : string
; B : string
}
let record = { A = "A"; B = "B" }
let record = { record with A = "new A" } //copy or overwrite?
Since I am overwriting record does the compiler copy or overwrite? Are there performance concerns either way?
It makes the copy.
Copy-and-update Record expression
*A copy-and-update record expression elaborates as if it were a record expression written as follows:
let v = expr in { field-label1 = expr1 ; … ; field-labeln = exprn; F1 = v.F1; ... ; FM = v.FM }
where F1 ... FM are the fields of R that are not defined in field-initializers and v is a fresh variable.*
This
type T = {
A : string
B : string
}
let x = { A = "a"; B = "b" }
let y = { x with A = "aa" }
is equivalent to this
class T {
public readonly string A;
public readonly string B;
public T(string a, string b) {
A = a;
B = b;
}
}
var x = new T("a", "b");
var y = new T("aa", x.B);

f# overwrite array access operator .[]

in F#, I want to make a type of indexed array, so I can access the element by either .[i] or .[index_names] and by slice notation with index .. Is it possible to overwrite .[] like this? thanks.
define overloaded indexer in your type:
type MyIndexedArray<'T>() =
member this.Item(i : int) : 'T = Unchecked.defaultof<_>
member this.Item(name : string) : 'T = Unchecked.defaultof<_>
member this.GetSlice(a : int option, b : int option) : 'T = Unchecked.defaultof<_>
let arr = new MyIndexedArray<int>()
let a = arr.[1]
let b = arr.["name"]
let c = arr.[1..2]
let d = arr.[1..]
let e = arr.[..3]
let f = arr.[*]

Resources