I am trying to use the railway programming in F# using result as described in Scott Wlaschin's book 'Domain modeling made functional'. Normally a function has the structure
let functionName parameter : Result<ResultType, ErrorType> =
result {
let! resultValue = someValidationAndTransformation parameter
return resultValue
}
But I want to return also some calculated fields, in both to Ok and the Error case. The best I could come up with was
let functionName parameter : Result<ResultType, ErrorType> * CalculatedFields =
let mutable calculatedFields = {some defaultvalue}
let result =
result {
let! resultValue = someValidationAndTransformation parameter
let calculatedField = someCalculation resultValue
calculatedFields <- {calculatedFields with calculatedField}
return resultValue
}
result, calculatedFields
This mutable field does not look nice. Is there a better way to get the calculated fields in both Ok and Error case?
I would use a match in this situation:
let functionName parameter : Result<ResultType, ErrorType> * CalculatedFields =
let result = someValidationAndTransformation parameter
let calculatedFields =
match result with
| Ok x -> someCalculation x
| Error e -> { some defaultvalue }
result, calculatedFields
Related
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.
I have the following types:
type GoodResource = {
Id:int;
Field1:string }
type ErrorResource = {
StatusCode:int;
Description:string }
I have the following discriminated union:
type ProcessingResult =
| Good of GoodResource
| Error of ErrorResource
Then want to have a function that will have a return type of the discriminated union ProcessingResult:
let SampleProcessingFunction value =
match value with
| "GoodScenario" -> { Id = 123; Field1 = "field1data" }
| _ -> { StatusCode = 456; Description = "desc" }
Is what I am trying to do possible. The compiler is giving out stating that it expects GoodResource to be the return type. What am I missing or am I completely going about this the wrong way?
As it stands, SampleProcessingFunction returns two different types for each branch.
To return the same type, you need to create a DU (which you did) but also specify the case of the DU explicitly, like this:
let SampleProcessingFunction value =
match value with
| "GoodScenario" -> Good { Id = 123; Field1 = "field1data" }
| _ -> Error { StatusCode = 456; Description = "desc" }
You might ask "why can't the compiler figure out the correct case automatically", but what happens if your DU has two cases of the same type? For example:
type GoodOrError =
| Good of string
| Error of string
In the example below, the compiler cannot determine which case you mean:
let ReturnGoodOrError value =
match value with
| "GoodScenario" -> "Goodness"
| _ -> "Badness"
So again you need to use the constructor for the case you want:
let ReturnGoodOrError value =
match value with
| "GoodScenario" -> Good "Goodness"
| _ -> Error "Badness"
You have to state the case of the union type you want to return in either branch.
let SampleProcessingFunction value =
match value with
| "GoodScenario" -> { Id = 123; Field1 = "field1data" } |> Good
| _ -> { StatusCode = 456; Description = "desc" } |> Error
I suggest to read this excellent articles by Scott Wlaschin Railway Oriented Programming
{ Id = 123; Field1 = "field1data" } is a value of type GoodResource, not of type ProcessingResult. To create a value of type ProcessingResult, you need to use one of its two constructors: Good or Error.
So your function can be written like this:
let SampleProcessingFunction value =
match value with
| "GoodScenario" -> Good { Id = 123; Field1 = "field1data" }
| _ -> Error { StatusCode = 456; Description = "desc" }
I am rewriting a C# library to F# and I need to translate the following code
bool success;
instance.GetValue(0x10, out success);
what is the equivalent of the out keyword in F#?
Neither wasatz's answer nor Max Malook's is complete. There are three ways of calling methods with out parameters. The second and third ways also work with ref parameters.
For the examples, assume the following type:
open System.Runtime.InteropServices //for OutAttribute
type SomeType() =
member this.GetValue (key, [<Out>] success : bool byref) =
if key = 10 then
success <- true
"Ten"
else
success <- false
null
Assume also that we have an instance of that type:
let o = SomeType()
Option 1
You can let the F# compiler handle the out parameter by tupling it with the return value:
let result1, success1 = o.GetValue 10
let result2, success2 = o.GetValue 11
Running the above lines in F# interactive yields
val success1 : bool = true
val result1 : string = "Ten"
val success2 : bool = false
val result2 : string = null
Option 2
You can use a mutable value, passing its address with the & operator:
let mutable success3 = false
let result3 = o.GetValue (10, &success3)
let mutable success4 = false
let result4 = o.GetValue (11, &success4)
In F# interactive, the result is
val mutable success3 : bool = true
val result3 : string = "Ten"
val mutable success4 : bool = false
val result4 : string = null
This option is best when you are delegating to another method, since you can pass the calling method's out parameter directly to the called method. For example, if you are implementing a wrapper around IDictionary<_,_>, you can code the TryGetValue method as
//...
interface IDictionary<'TKey, 'TValue> with
member this.TryGetValue (key, value) = inner.TryGetValue (key, &value)
//...
Option 3
You can use a reference cell:
let success5 = ref false
let result5 = o.GetValue (10, success5)
let success6 = ref false
let result6 = o.GetValue (11, success6)
The output:
val success5 : bool ref = {contents = true;}
val result5 : string = "Ten"
val success6 : bool ref = {contents = false;}
val result6 : string = null
Warning!
Be careful not to use the ref keyword as you would in C# for an in/out parameter. For example, the following does not yield the desired result:
let success7 = false
let result7 = o.GetValue (10, ref success7)
The output:
val success7 : bool = false
val result7 : string = "Ten"
Why does success7 hold the value false? Because success7 is an immutable variable.
In C#, ref calls attention to the fact that you are passing a reference to a variable as the argument for a ref parameter. It simply serves as insurance that the programmer of the caller is aware that the variable may be modified by the called method. In F# however, ref creates a new reference cell holding a copy of the value of the following expression.
In this case, we are making a reference cell that holds the value copied from the success7 variable, but not assigning that new reference cell to any variable. We then pass that reference cell to the GetValue method, which modifies the content of the reference cell. Because the calling method has no variable pointing to the modified cell, it has no way of reading the new value of the reference cell.
You should probably return an option or a tuple instead. Because F# has pattern matching you really don't need out parameters since there are better ways to return more than one value from a function.
So, something like this would be more idiomatic
let (value, success) = instance.GetValue(0x10)
where instance.GetValue is a
unit -> ('a, bool)
Or you could return an option and do something like
match instance.GetValue(0x10) with
| Some value -> doStuff value
| None -> failwith "Oops!"
You have to use a reference cell.
let success = ref false
instance.GetValue(0x10, success)
// access the value
!success
I think it's also worth mentioning here that the value of the out parameter doesn't have to be initialized.
It is possible to do the following:
let mutable success3 = Unchecked.defaultof<bool>
let result3 = o.GetValue (10, &success3)
This might be usefull in scenarios where you are calling a .NET library function with arrays as output parameters, i.e:
let mutable currFeatures = Unchecked.defaultof<PointF[]>
let mutable status = Unchecked.defaultof<byte[]>
let mutable trackError = Unchecked.defaultof<float32[]>
CvInvoke.CalcOpticalFlowPyrLK(
previousFrame,
nextFrame,
previousPoints,
Size(15,15),
2,
MCvTermCriteria(10, 0.03),
//Out params
&currFeatures,
&status,
&trackError,
//---------
LKFlowFlag.UserInitialFlow)
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
I'm writing a parser for CSV data, and am trying to determine how to handle records
that are blank ("") or contain character data ("C"). The parser code I have below works great, but forces me to deal with the float conversions later. I'd like to be able to just make my string[][] a float[][], and handle the conversions when I parse the file, but I notice that it blows up with any non-numeric data. Ideally there would be no non-numeric or blank values, but they are unavoidable, and as such, have to be dealt with.
Can someone possibly recommend a concise approach to attempt to convert to Double, and then if it doesn't work, replace with Double.NaN instead? (Without sacrificing much performance if possible). Thank you.
let stringLine = [| "2.0"; "", "C"|]
let stringLine2Float = Array.map float stringLine
//desiredFloatArray = [| 2.0; Double.NaN; Double.NaN |]
type csvData = { mutable RowNames: string[]; mutable ColNames: string[]; mutable Data: string[][] }
let csvParse (fileString: string) =
let colNames = ((fileLines fileString |> Seq.take 1 |> Seq.nth 0).Split(',')).[1..]
let lines = fileLines fileString |> Seq.skip 1 |> Array.ofSeq
let rowNames = Array.init lines.Length string;
let allData : string [][] = Array.zeroCreate rowNames.Length
for i in 0..rowNames.Length - 1 do
let fields = lines.[i].Split(',')
allData.[i] <- fields.[1..]
rowNames.[i] <- fields.[0]
{ RowNames = rowNames; ColNames = colNames; Data = allData }
Use this instead of the built-in float conversion:
let cvt s =
let (ok,f) = System.Double.TryParse(s)
if ok then f else nan