How to combine (?) two Results together - f#

I'm starting to play around with F# and challenged myself to write a FizzBuzz (ikr, dream big).
After watching a couple of Scott Wlaschin talks, I'm trying to refactor my mess by using all those cool maps and binds and etc, but I found myself being stuck on merging 2 results together.
What i have here is this function (Result<int, string> * Result<int, string>) -> Result<int list, string>:
let rangeToList (from, ``to``) =
match from, ``to`` with
| Ok first, Ok last -> Ok [ first..last ]
| Error error, Ok _ -> Error error
| Ok _, Error error -> Error error
| Error error1, Error error2 -> Error(error1 + "; " + error2)
Results here are the results of parsing int from string (console input).
I have a feeling, this notation can be simplified somehow, but I can't seem to figure out how. Any tips?

I think you are fairly close to the simplest way of doing this. There are only a few tweaks I can think of.
First, I would really advice against using ``to`` as a variable name. It can be done, but it just looks ugly!
Second, you can reduce the number of cases to just three - if you first match the OK, Ok and Error, Error cases, you know that you now have one Error and one Ok, so you can join those using the | (or) pattern and always return the Error result:
let rangeToList (from, last) =
match from, last with
| Ok first, Ok last -> Ok [ first..last ]
| Error error1, Error error2 -> Error(error1 + "; " + error2)
| Error error, _ | _, Error error -> Error error
Third, if you are passing the two arguments to the function as a tuple, you could further condense this using the function keyword which defines a function that immediately matches on the argument (but this would not work if the arguments were space separated):
let rangeToList = function
| Ok first, Ok last -> Ok [ first..last ]
| Error error1, Error error2 -> Error(error1 + "; " + error2)
| Error error, _ | _, Error error -> Error error
I think this solution works great. If you wanted something more clever using higher-order functions (but I really do not think this is needed here), you could define a zip function that takes two results and combines them - producing a pair of values and collecting all errors into a list:
module Result =
let zip r1 r2 =
match r1, r2 with
| Ok v1, Ok v2 -> Ok (v1, v2)
| Error e1, Error e2 -> Error [e1; e2]
| Error e, _ | _, Error e -> Error [e]
Using this as a helper, you could now rewrite your original function as:
let rangeToList2 (from, last) =
Result.zip from last
|> Result.mapError (String.concat "; ")
|> Result.map (fun (first, last) -> [ first..last ])
I think this is nice, but perhaps unnecessarily clever. It is not much shorter than your first version and it is certainly not much easier to understand.

Your code is fine as is, but I think the pattern you're sensing is called an "applicative". Applicatives are like a lite version of monads, so instead of Bind, the important function is called MergeSources in F#. You can use this to create a simple computation builder, like this:
type ResultBuilder() =
member _.BindReturn(result, f) =
result |> Result.map f
member _.MergeSources(result1, result2) =
match result1, result2 with
| Ok ok1, Ok ok2 -> Ok (ok1, ok2)
| Error error, Ok _
| Ok _, Error error -> Error error
| Error error1, Error error2 -> Error (error1 + "; " + error2)
let result = ResultBuilder()
And you can then use this to implement an elegant version of rangeToList with a computation expression, like this:
let rangeToList (from, ``to``) =
result {
let! first = from
and! last = ``to``
return [ first..last ]
}
The nice thing about this approach is that it separates the general Result-wrangling logic in MergeSources from the domain-specific logic in rangeToList. This allows you to reuse the same result builder freely in other domains as well.
More details here and here.

Related

Can I extend a generic type? in F#

I have a DU representing error states:
type ExchangeError =
| NoError
| ServiceUnavailable
| HttpError of HttpStatusCode * string
...
and I have one return type used everywhere:
Result<'a, ExchangeError>
Is there a way for me to add a method to that type that would work like this pseudo-solution:
type Result<'a, ExchangeError> with
member this.GetOrFail
match this with
| Ok data -> data
| Error e -> failwith $"error: {e}"
to be used like this:
let result = myData.GetOrFail
I find myself typing this over and over when doing exploration code and I don't care about handling errors, etc; I want either a result or stop at that point.
So, I thought a helper method may be useful.
But how can this be achieved?
There's nothing in GetOrFail that relies on the error type, so you can just make a generic extension:
type Result<'a, 'err> with
member this.GetOrFail =
match this with
| Ok data -> data
| Error e -> failwith $"error: {e}"
But if you really want this extension to apply only to Result<'a, ExchangeError>, you can do it with a C#-style extension member:
open System.Runtime.CompilerServices
[<Extension>]
type Extensions() =
[<Extension>]
static member GetOrFail (res : Result<'a, ExchangeError>) =
match res with
| Ok data -> data
| Error e -> failwith $"error: {e}"
In this case, you have to invoke it as a method, rather than a property, but I figure that's still good enough.
I don't think you can add extension methods to a partially constrained generic type like that. Probably the best way is to just use a function:
module ExchangeError =
let getOrFail (x: Result<'a, ExchangeError>) =
match x with
| Ok data -> data
| Error e -> failwith $"error: {e}"
let result = getOrFail myData

How can I get values with discriminited union type from recursive function

I am trying to obtain a specific value from one list with a multiple recursion so I have :
type PowerSystem =
| System of string * int
| Junction of string * List<PowerSystem>
let Starship =
Junction("Core",
[
Junction("Users",
[
System("Main Computer",-10);
System("Library Computer",-10);
Junction("Defence",)]
let rec JunctionPath (pSystem:PowerSystem) =
match pSystem with
| Junction(name,aList) -> SplitList2 aList
| System(name,aNumber) -> [name]
and SplitList2 list =
match list with
| [] -> printfn "%A" []
| head::tail -> printfn "%A" List.filter (fun e->e="Port Phasers" (JunctionPath head)#(SplitList2 tail))
JunctionPath Starship
I get error FS0001: The type ''a -> string list' does not match the type 'unit'
I want to get the name of junctions when the system is called Main Computer but I can't call other functions. I tryed in different ways to get those values but I can't found the way. Thanks in advance
SplitList2 only has the side effect of printfn hence returns unit ().
In JunctionPath the first branch returns a list of string - [name] - and the second a unit due to calling SplitList2. This is not allowed as both (in general all) pattern match branches should return the same type. This is why you get your error "error FS0001: The type ''a -> string list' does not match the type 'unit'"
(It would be clearer if you, in future, note the line references in the error as that points to the problematic line).
Now in answer to your last point:
I want to get the name of junctions when the system is called Main
Computer but I can't call other functions. I tryed in different ways
to get those values but I can't found the way.
this does not make sense since what is "Port Phasers"? Anyway, without testing, I have modified SplitList2 to return a list on either branch. Then we pipe the result of JunctionPath into a printfn. However the logic of the line List.filter (fun e->e="Port Phasers" (JunctionPath head)#(SplitList2 tail)) still does not make sense, so I updated it as I think you meant it (although you should have had another error for this?). (This is not tail recursive and can be improved but one step at a time)
type PowerSystem =
| System of string * int
| Junction of string * List<PowerSystem>
let Starship =
Junction("Core",
[
Junction("Users",
[
System("Main Computer",-10);
System("Library Computer",-10);
Junction("Defence",)]
let rec JunctionPath (pSystem:PowerSystem) =
match pSystem with
| Junction(name,aList) -> SplitList2 aList
| System(name,aNumber) -> [name]
and SplitList2 list =
match list with
| [] -> []
| head::tail -> List.filter (fun e->e="Port Phasers") (JunctionPath head)#(SplitList2 tail))
JunctionPath Starship |> printfn "%A%

Prevent shadowing of Ok and Error with FParsec?

Suppose I have a test like this:
module MyTests
open Xunit
open FParsec
open FsUnit.Xunit
open MyParsers
[<Fact>]
let ``pfoo works as expected`` () =
let text = "blahblahblah"
let actual =
match run pfoo text with
| Success (x, _, _) -> Result.Ok x
| Failure (s, _, _) -> Result.Error s
let expected : Result<Foo, string> =
Result.Ok
{
Foo = "blahblahblah"
}
expected
|> should equal actual
open FParsec will shadow Ok so that I need to fully qualify it like Result.Ok.
This is pretty annoying. Is there a good way to "open" Result again so that I can write Ok unqualified?
It's not Result that you need to "open", but Microsoft.FSharp.Core, which is the module in which Result and both its constructors are defined. This module is open by default, but you can open it again to have its definitions closer in the scope:
open Xunit
open FParsec
open FsUnit.Xunit
open MyParsers
open Microsoft.FSharp.Core
Alternatively, you can alias just the Ok identifier:
let Ok = Result.Ok
let x = Ok "foo" // x : Result<string, _>
I prefer this latter method, because it minimizes the impact surface and thus reduces the chance of unexpected surprises.
The downside is that the aliased Ok won't work for pattern matching:
match x with
| Ok y -> ... // This is Ok from FParsec
If you need pattern matching as well, you'll have to alias the matcher too:
let (|Ok|Error|) x = match x with | Result.Ok o -> Ok o | Result.Error e -> Error e
At which point I would probably fall back to reopening the module.

using Result<> without a type in F#

I would like to do something like this:
let a x : Result<_, string> =
match x with
| 1 -> Ok
| _ -> Error "not 1"
this will not compile.
Is there a way to not specify an ok type and return nothing?
Not an experienced F# coder, but my understanding is that the way of indicating "no return value" is to use a Unit.
This compiles. Would it suffice for what you're doing?
let a x =
match x with
| 1 -> Ok ()
| _ -> Error "not 1"
Or with an explicit return type:
let a x : Result<Unit, string> =
match x with
| 1 -> Ok ()
| _ -> Error "not 1"
Given that Ok is a parameterized type, I don't think there's a way to get Ok by itself to work for what you're doing.

Type test pattern matching for DUs

With DU (Discriminated Union types), how do I perform a type test pattern matching ?
I have this following running code :
type IU =
|Int of int
|Unit of Unit
let x = IU.Int(3)
let y = IU.Unit(())
let z = [3.14]
let showI (v) =
match box v with
| :? IU ->
match v with
| Int(_) -> "an IU int"
|_ -> "not a IU.int"
|_ -> "not a IU.int"
But I am not happy with the inner match in the showI function. I would have preferred something like :
let showI (v) =
match box v with
| :? IU.Int -> "an int"
|_ -> "not a IU.int"
which doesn't compile (error : the type Int is not defined).
Is there an obvious syntax I missed ? Thanks.
Note : showI function accepts a variable with an unknowned type ; that is the reason for the smelly box v.
As others have pointed out, I don't think there's any built-in language feature that lets you do this. However, you could define an active pattern that performs the type test:
let (|IsIU|_|) (candidate : obj) =
match candidate with
| :? IU as iu -> Some iu
| _ -> None
This active pattern has the type obj -> IU option.
You can compose your own custom active pattern with standard patterns, like this:
let showI = function
| IsIU (IU.Int i) -> "an IU int"
| _ -> "not a IU.int"
In this example, the custom IsIU active pattern has been composed with a standard identifier pattern that matches on the IU.Int case.
Here's a sample FSI session showing usage with the x, y, and z values given in the OP:
> showI x;;
val it : string = "an IU int"
> showI y;;
val it : string = "not a IU.int"
> showI z;;
val it : string = "not a IU.int"
Staying within the context of your question I believe what you are missing is that IU.Int is not a type, but a case Int of discriminated union type IU. When you write
let x = IU.Int(3)
the type of value x is IU, not IU.Int. That's why compiler barks upon your attempt to match obj to UI.Int with :? pattern.
In a broader context, it seems you try approaching F# a-la dynamic language of Javascript kind, which it is not. Exaggerating a bit, you seemingly try using functions operating upon arguments of only one type obj and hence spending substantial run-time effort on dynamic discovery of specific argument types with wide opportunities for making mistakes on the way.
Such approach misses the whole point of F# idiomatic DU use case, which is disassembling of a value that is known to be statically typed as IU by pattern match machinery to specific union case (IU.Int or IU.Unit):
let showI (v : IU) = // explicit argument type is added to illuminate the point
match v with
| IU.Int(x) -> sprintf "a IU.Int(%i) value" x
| _ -> "a IU.Unit"
So, if you by mistake try calling showI with argument that is not of type IU, compiler will catch the erroneous use of your function with argument of wrong type right away and simply will not build the executable form of your code until the mistake is corrected.
EDIT: Idiomatic use aside you may get away with a single match, indeed, with the help of when guard, like in a snippet below, although this is a nasty hack:
open Microsoft.FSharp.Reflection
let showI (v) =
match box v with
| :? IU as x when (fst(FSharpValue.GetUnionFields(x, typeof<IU>))).Name.Equals("Int")
-> "an IU.Int"
| _ -> "not an IU.Int"

Resources