^b :(static member TryCreate : 'a -> Result<^b, 'c>)
This can be useful when constructing types for collecting construction result errors associated with passed-in parameter names, as the example below demonstrate.
Examples
Example 1
Making illegal states unrepresentable is a common practice in F#. A common way to do it is to have a type, say MyType, with a private constructor and a TryCreate member that returns a Result<MyType, 'a>, like shown below:
typeLongitude=private Longitude offloatwithmember this.Value =let(Longitude lng)= this in lng// float -> Result<Longitude, string>static member TryCreate(lng :float)=if lng >=-180.&& lng <=180.then Ok (Longitude lng)else Error $"%A{lng} is a invalid longitude value"
Let's assume that we have few more similar types as below
Assume furthermore that the types above are used in the following types:
And that we have the following functions to create these composed types:
Here the types of the Result.tryCreate lines are inferred, and the types' TryCreate member is used to construct them.
These errors can then for example be returned in an API response:
When serialized:
Example 2
In Example 1, we collected all the error messages. But what if we wanted to stop on the first error? One way to do this is to make use of the result computation expression instead of using infix operators from Result module.
Example 3
In the examples above, we assume that a location is always required for creating a post. Let's assume that the requirement is changed and now the location is optional:
Then validateCreatePostRequest can be rewritten using the Option.traverseResult function as below:
Note: We are using the <!> operator in the validateCreatePostRequest instead of <!^> operator as the right side result is returning a list of errors (Result<Location option, (string * string) list>).
type Latitude = private Latitude of float with
member this.Value =
let (Latitude lat) = this
lat
// float -> Result<Latitude, string>
static member TryCreate (lat : float) =
if lat >= -90. && lat <= 90. then
Ok (Latitude lat)
else
Error $"%A{lat} is a invalid latitude value"
open System
type Tweet = private Tweet of string with
member this.Value =
let (Tweet tweet) = this in tweet
static member TryCreate (tweet : string) =
if String.IsNullOrEmpty tweet then
Error "Tweet shouldn't be empty"
elif tweet.Length > 280 then
Error "Tweet shouldn't contain more than 280 characters"
else Ok (Tweet tweet)
type Location = {
Latitude : Latitude
Longitude : Longitude
}
type CreatePostRequest = {
Tweet : Tweet
Location : Location
}
let location lat lng =
{Latitude = lat; Longitude = lng}
let createPostRequest lat long tweet =
{Tweet = tweet; Location = location lat long}
type LocationDto = {
Latitude : float
Longitude : float
}
type CreatePostRequestDto = {
Tweet : string
Location : LocationDto
}