I have the following type in F#:
type CodeNameError(CodeNameCombination: (Code*Name)[]) =
member this.CodeNameCombinations = CodeNameCombination
Is there a way to turn the (Code*Name)[] into a named tuple array in F#?
In c# I would do something like:
public CodeNameError((Code code, Name name)[] codeName)
{
CodeNameCombination = codeName
}
F# does not have named tuples in the same way in which C# has them, but there are a couple of alternatives. My preferred option would actually be to just define a new record type for the Code * Name pair. If you get into a situation where you want to name things, a record is a good choice and it takes 1 line of code:
type NamedCode = { Name:Name; Code:Code }
type CodeNameError(codeNameCombination:NamedCode[]) =
member this.CodeNameCombinations = codeNameCombination
CodeNameError [| { Code = "1+1"; Name = "test" } |]
If you do not want to define a type (but I'm not sure why you wouldn't want to do this), you could use anonymous records:
type CodeNameError(CodeNameCombination: {| code:Code; name:Name |}[]) =
member this.CodeNameCombinations = CodeNameCombination
CodeNameError [| {| code = "1+1"; name = "test" |} |]
Related
I am new in F# and I wonder whether is there a possibility (unsing NUnit) to construct a test class multiple parameters in its constructor with some similar construction - following end up with
Message:
OneTimeSetUp: No suitable constructor was found
// if data with one parameter, no problem to run the tests
// the data not only the constants at the compile time, so need to work TestFixtureSoource attribute.
type SimpleFixtureArgs =
static member Source = [| (String.Empty, String.Empty); ("hello", "hello") |]
[<TestFixtureSource(typeof<SimpleFixtureArgs>, "Source")>]
type ``simple tests class``(text, text2) =
[<Test>]
member this.``simple test``() =
let expexted = text
let actual = text2
Assert.AreEqual(expexted, actual)
Since removing the one parameter (e.g. the text2) and having appropriate one-parameter TestFixtureSource it started to work...
So the question is how to write the NUnit test to work with TestFixtureSource with multiple parameters?
TIA,
Mojmir
Individual items of text fixture source should be object arrays or derive from the TestFixtureParameters class (NUnit documentation). But tuple is not an object array - it's a single object. So change source property to return IEnumerbale (or array) of arrays:
type SimpleFixtureArgs =
static member Source = seq {
[| String.Empty; String.Empty|]
[| "hello"; "hello"|]
}
Later, I needed to deal with different types of parameters.
There is slightly modified code in F# from the previous answer, which worked for me.
type SimpleFixtureArgs2 =
static member Source : seq<obj []> =
seq {
yield [| String.Empty; String.Empty; 1; 1 |]
yield [| "hello"; "hello"; 2; 2 |]
}
[<TestFixtureSource(typeof<SimpleFixtureArgs2>, "Source")>]
type ``simple tests2 class``(text1, text2, num1, num2) =
[<Test>]
member this.``simple strings and integers test``() =
let expextedText = text1
let actualText = text2
Assert.AreEqual(expextedText, actualText)
Assert.AreEqual(num1, num2)
Beginner in F# here
I want to create a type, which is a sequence of another concrete type (Event) with at least one element. Any other elements can be added anytime later. Normally in C# I would create a class with a private List<Event> and public methods.
But I want to do it with a functional approach and not imitate the C# approach. Or at least try.
My train of thought:
Let's create a type "of seq" and give it a constructor requiring instance of the Event type
type Event = Event of string
type PublishedEvents = EventList of seq<Event> with
static member create (event:Event) = EventList(Seq.singleton event)
Now let's add an "add" method for adding another optional Event instances
type PublishedEvents with
member this.add(event:Event) = Seq.append this [event]
But that doesn't work, F# complains that "this" is not compatible with seq<'a>.
So I tried this:
type PublishedEvents with
member this.add (event:Event) : PublishedEvents = EventList(Seq.append this [event])
Now it complains that "this" is not compatible with seq<Event>...which is confusing me now since few lines above it says EventList of seq<Event> ... so I guess I need to somehow convert EventList back to seq<Event> so I can then use Seq.append ?
let convertFunction (eventList:PublishedEvents) : seq<Event> = ???
But I have no idea how to do this.
Am I even going the right direction? Is it better for this to mimic a C# class with a backing field? Or am I missing something?
The actual sequence of events is wrapped inside an EventList discriminated union case.
You can unwrap it and re-wrap it like this:
type PublishedEvents with
member this.add(event:Event) =
match this with
| EventList events -> Seq.append events [event] |> EventList
However, I have to question the value of creating this PublishedEvents type in the first place, if it's just a single EventList case containing a sequence that requires you to wrap and unwrap values repeatedly.
Also, please be aware that this add method doesn't change the existing PublishedEvents. It creates a new one with a new sequence of events, because of the way that Seq.append works, because seq<'a> is actually just F#'s name for System.Collections.Generic.IEnumerable<'a>).
Furthermore, your approach does not prevent creation of a non-empty event sequence. EventList is a public constructor for PublishedEvents so you can just write:
EventList []
A simple way to make the type system enforce a non-empty sequence is this:
type NonEmptySeq<'a> = { Head : 'a; Tail : seq<'a> } with
static member Create (x:'a) = { Head = x; Tail = [] }
member this.Add x = { this with Tail = Seq.append this.Tail [x] }
let a = NonEmptySeq.Create (Event "A")
let b = a.Add (Event "B")
But again, these sequences are immutable. You could do something similar with a C# List<'a> if you need mutation. In F# it's called a ResizeArray<'a>:
type NonEmptyResizeArray<'a> = { Head : 'a; Tail : ResizeArray<'a> } with
static member Create (x:'a) = { Head = x; Tail = ResizeArray [] }
member this.Add x = this.Tail.Add x
let a = NonEmptyResizeArray.Create (Event "A")
a.Add (Event "B")
I propose that you go even more functional and not create members for your types - have it done in your functions. For example this would achieve the same and I would argue it's more idiomatic F#:
type Event = Event of string
type PublishedEvents = EventList of Event * Event list
let create e = EventList (e,[])
let add (EventList(head,tail)) e = EventList(e,head::tail)
let convert (EventList(head,tail)) = head::tail |> Seq.ofList
let myNewList = create (Event "e1")
let myUpdatedList = add myNewList (Event "e2")
let sequence = convert myUpdatedList
val sequence : seq = [Event "e2"; Event "e1"]
On the other hand if your aim is to interop with C# your approach would be easier to consume on C# side.
I am using the CsvTypeProvider to map data from CSV files into my own data structures. This works splendidly, except for that I have to repeat the mapping function every time:
type GamesFile = CsvProvider<"./data/15.csv">
let games15 = GamesFile.Load("./data/15.csv").Rows |> Seq.map ( fun c -> { Division = c.Div; Date = c.Date; HomeScore = c.HomeScore; AwayScore = c.AwayScore })
let games16 = GamesFile.Load("./data/16.csv").Rows |> Seq.map ( fun c -> { Division = c.Div; Date = c.Date; HomeScore = c.HomeScore; AwayScore = c.AwayScore })
When I try moving it to a function, I am told that "Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved."
This makes sense, but how can I tell a mapping function what type it is when the type is inferred from the contents of the CSV? How is this normally solved?
The type provider generates a type representing the row and it exposes it as a nested type of the main provided type - in your case aliased as GamesFile.
This is not entirely obvious, because the editors will show tooltip with something like
CsvFile<...>.Row so it does not show the name of the alias, but it suggests Row is a nested type. To use the type in your code, you can just write GamesFile.Row, so you need something like this:
type GamesFile = CsvProvider<"./data/15.csv">
let mapRows (rows:seq<GamesFile.Row>) =
rows |> Seq.map (fun c ->
{ Division = c.Div; Date = c.Date; HomeScore = c.HomeScore; AwayScore = c.AwayScore })
let games15 = GamesFile.Load("./data/15.csv").Rows |> mapRows
let games16 = GamesFile.Load("./data/16.csv").Rows |> mapRows
Say I have an interface ICache which defines two functions, Function1 and Function2 and I use an object expression to implement it, but I also want to add a helper function:
let WebCache =
{ new ICache with
member __.HelperFunction = //this doesn't work!
member __.Function1 = foo
member __.Function2 = bar
}
F# seems to not allow you to add any methods that are not part of the interface. Is there a workaround? If I want to do this, should I not be using an object expression in the first place?
You can define the helper function as an ordinary (local) function outside of the object expression:
let WebCache =
let helper n =
printfn "Helping %" n
{ new ICache with
member __.Function1 = helper 1
member __.Function2 = helper 2 }
This question is in follow up to an earlier question, Preserving Field names across the F#/C# boundary
Because of the current limitation encountered with F# type providers (see the earlier question), I want to map the type-provider-generated list to my own list of records, in which the record is, in part,
type inspection = {
inspectionID : string;
inspectorID : int;
EstablishmentID : string;
EstablishmentName : string; // other members elided
}
I think the way to do this will use Seq.map, but I am not certain. (Recall I am doing a learning exercise.) So here is what I tried:
type restaurantCsv = CsvProvider<"C:\somepath\RestaurantRatings2013.csv",HasHeaders=true>
// which generates a type, but it is an "erased" type, so member names do not propogate
// over to C#.
type RawInspectionData(filename : string) =
member this.allData = restaurantCsv.Load(filename) // works fine
member this.allInspections =
this.allData.Data
|> Seq.map(fun rcrd -> new inspection[{inspectionID = rcrd.InspectionID;}])
and, of course, the complete statement would have the other member names as part of the inspection, here elided for brevity. Someone pointed me to p 43 of F# For Scientists, which is why I thought to use this format with the curly braces. But this yields a syntax error, "Unexpected symbol '{' in expression. Expected ',', ']' or other token."
Hopefully, though, this snippet is adequate to show what I would like to do, create a Generated Type from the Erased Type. How can I accomplish this?
Your code is going in the right direction. When using Seq.map (which is like Select in LINQ), you need to turn a single element of the original sequence into a single element of the new sequence. So the lambda function just needs to create a single instance of the record.
A record is constructed using { Field1 = value1; Field2 = value2; ... } so you need:
type RawInspectionData(filename : string) =
let allData = restaurantCsv.Load(filename) // works fine
member this.allInspections =
allData.Data
|> Seq.map(fun rcrd -> {inspectionID = rcrd.InspectionID})
I also changed allData from a member to a local let definition (which makes it private field of the class). I suppose that your original code new inspection[{...}] tried to create a singleton array with the element - to create an array you'd write [| { Field = value; ... } |] (and the compiler would infer the type of the array for you). But in this case, no arrays are needed.