How do I implement a method with a variable number of arguments?
In C#, we can use the params keyword:
public class MyClass
{
public static void UseParams(params int[] list)
{
for (int i = 0; i < list.Length; i++)
{
Console.Write(list[i] + " ");
}
Console.WriteLine();
}
}
So how can I do this in F#?
type MyClass() =
member this.SomeMethod(params (args:string array)) = ()
I receive the following error from the code above:
The pattern discriminator 'params' is not defined
You can use ParamArrayAttribute:
type MyClass() =
member this.SomeMethod([<ParamArray>] (args:string array)) = Array.iter (printfn "%s") args
then:
let mc = MyClass()
mc.SomeMethod("a", "b", "c")
Related
The current code:
class A {
List<int> listOne = [];
List<int> listTwo = [];
List≤int> listOfLists = [
...listOne,
...listTwo
];
}
Results in the following error for each list with an spread operator (...):
error: The instance member 'listOne' can't be accessed in an initializer.
error: The instance member 'listTwo' can't be accessed in an initializer.
What I know:
listOne etc. can't be referenced in another initializer
So what I tried: https://dart.dev/tools/diagnostic-messages#implicit_this_reference_in_initializer
class C {
int x;
C() : x = defaultX;
static int get defaultX => 0;
}
Unfortunately, I do not know how to translate that to solve my problem.
Can you guys help me out?
You need to explicitly make a constructor and do the assignment there.
class A {
List<int> listOne = [];
List<int> listTwo = [];
List<int> listOfLists;
A() {
listOfLists = [...listOne, ...listTwo];
}
}
If you're using null-safety then you should add the late keyword.
class A {
List<int> listOne = [];
List<int> listTwo = [];
late List<int> listOfLists;
A() {
listOfLists = [...listOne, ...listTwo];
}
}
I want list subtype to another subtype how can i?
List<type1> someList = new List<type1>();
I want convert this list to
List<type2> someList = new List<type2>();
I have both model with same string its possible? i try this
List<type2> tList = new List();
for (int i = 0; i < snapshot.data.length; i++) {
tList.add(snapshot.data[i]);
}
error:
type 'type1' is not a subtype of type 'type2'
final someList = <TypeA>[];
final convertedList = List<TypeB>.from(someList);
A simple example would be:
final numList = <num>[1, 2];
final intList = List<int>.from(numList);
You might run into errors, if your num contains a double, in that case, you can use map:
final numList = <num>[1, 2.0];
final intList = numList.map((e) => e.toInt()).toList();
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}"
I have the following struct defined.
struct Person {
var firstName :String
var lastName :String
var active :Bool
}
I have created a collection of Person as shown below:
var persons :[Person] = []
for var i = 1; i<=10; i++ {
var person = Person(firstName: "John \(i)", lastName: "Doe \(i)", active: true)
persons.append(person)
}
and Now I am trying to change the active property to false using the code below:
let inActionPersons = persons.map { (var p) in
p.active = false
return p
}
But I get the following error:
Cannot invoke map with an argument list of type #noescape (Person) throws
Any ideas?
SOLUTION:
Looks like Swift can't infer types sometimes which is kinda lame! Here is the solution:
let a = persons.map { (var p) -> Person in
p.active = false
return p
}
THIS DOES NOT WORK:
let a = persons.map { p in
var p1 = p
p1.active = false
return p1
}
There are exactly two cases where the Swift compiler infers the return
type of a closure automatically:
In a "single-expression closure," i.e. the closure body
consists of a single expression only (with or without explicit
closure parameters).
If the type can be inferred from the calling context.
None of this applies in
let inActionPersons = persons.map { (var p) in
p.active = false
return p
}
or
let a = persons.map { p in
var p1 = p
p1.active = false
return p1
}
and that's why
you have to specify the return type explicitly as in Kametrixom's answer.
Example of a single-expression closure:
let inActionPersons = persons.map { p in
Person(firstName: p.firstName, lastName: p.lastName, active: false)
}
and it would compile with (var p) in or (p : Person) in as well, so this has nothing to do with whether the closure arguments are given
explicitly in parentheses or not.
And here is an example where the type is inferred from the calling
context:
let a : [Person] = persons.map { p in
var p1 = p
p1.active = false
return p1
}
The result of map() must be a [Person] array, so map needs
a closure of type Person -> Person, and the compiler infers
the return type Person automatically.
For more information, see "Inferring Type From Context" and "Implicit Returns from Single-Expression Closures" in the
"Closures" chapter in the Swift book.
When using the brackets for arguments so that var works, you have to put the return type as well:
let inActionPersons = persons.map { (var p) -> Person in
p.active = false
return p
}
Swift 5
The accepted answer no longer works, as of Swift 5, anyway. Closures cannot have keyword arguments anymore which means that each element of the iteration must remain a constant. Therefore, to mutate structures using map, new elements must be initialized within each iteration:
let activePersons = persons.map { (p) -> Person in
return Person(firstName: p.firstName, lastName: p.lastName, active: true)
}
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);