How can I add to a type that contains an integer inside a Result of a discriminated union? - f#

I'm working on a single case discriminated union with a module to create instances of the type and return a Result of either Ok if the input was valid or Error otherwise. Here is what I have so far.
type ErrorMessage = string
type NonNegativeInt = private NonNegativeInt of int
module NonNegativeInt =
let create (inputInt:int) : Result<NonNegativeInt, ErrorMessage> =
if inputInt >= 0 then
Ok (NonNegativeInt inputInt)
else
Error ("inputInt must be >= 0")
let value (NonNegativeInt intVal) = intVal
I would like to add an integer to an instance of this type using the create function so it will block negatives. I've got the first test working this way.
[<Fact>]
member this.``NonNegativeInt test`` () =
let nonNegativeResult = NonNegativeInt.create 5
let newNonNegativeResult = match nonNegativeResult with
| Ok result ->
let intVal = NonNegativeInt.value result
let newIntVal = intVal + 1
NonNegativeInt.create newIntVal
| Error _ ->
nonNegativeResult
match newNonNegativeResult with
| Ok result ->
Assert.Equal(6, NonNegativeInt.value result)
| Error _ ->
Assert.Fail("Error creating new NonNegativeInt")
This is pretty much unusable this way. Is there a more concise way to accomplish this task without all the unwrapping, wrapping, and pattern matching? Is Result.bind the way to go?
Update 1 Trying Result.bind
This is a better, but still feels a bit clumsy. Maybe the NonNegativeInt module needs another function besides create and value to make this easier.
[<Fact>]
member this.``NonNegativeInt test2`` () =
let nni1 = NonNegativeInt.create 5
let nni2 = nni1
|> Result.bind (fun x -> NonNegativeInt.create ((NonNegativeInt.value x) + 1))
let expectedResult = NonNegativeInt.create 6
Assert.Equal(expectedResult, nni2)

Suggestion 1
You could use a computation builder to make the code cleaner:
type ResultBuilder() =
member _.Return(x) = Ok x
member _.ReturnFrom(res : Result<_, _>) = res
member _.Bind(res, f) = Result.bind f res
let result = ResultBuilder()
Then your example becomes:
let test () =
result {
let! nni = NonNegativeInt.create 5
return! NonNegativeInt.create (nni.Value + 1)
}
test () |> printfn "%A" // Ok NonNegativeInt 6
I also added a member to make it easier to access a NonNegativeInteger's value:
type NonNegativeInt =
private NonNegativeInt of int
with
member this.Value =
let (NonNegativeInt n) = this in n
Suggestion 2
Having an NNI type and then wrapping it in a Result is like wearing both a belt and suspenders. To simplify things further, you could get rid of the NNI type entirely, and just keep the validation logic:
module NonNegativeInt =
let create (inputInt:int) : Result<int, ErrorMessage> =
if inputInt >= 0 then
Ok inputInt
else
Error ("inputInt must be >= 0")
let test () =
result {
let! n = NonNegativeInt.create 5
return! NonNegativeInt.create (n + 1)
}
test () |> printfn "%A" // Ok 6
Suggestion 3
Alternatively, you could keep the NNI type and trust the caller to use it with valid values (without wrapping in a Result). This is what FsCheck does, for example:
///Represents an int >= 0
type NonNegativeInt = NonNegativeInt of int with
member x.Get = match x with NonNegativeInt r -> r
override x.ToString() = x.Get.ToString()
static member op_Explicit(NonNegativeInt i) = i

Related

How to make a lazy computational workflow?

I'm trying to write a computational workflow which would allow a computation which can produce side effects like log or sleep and a return value
A usage example would be something like this
let add x y =
compute {
do! log (sprintf "add: x = %d, y= %d" x y)
do! sleep 1000
let r = x + y
do! log (sprintf "add: result= %d" r)
return r
}
...
let result = run (add 100 1000)
and I would like the side effects to be produced when executeComputation is called.
My attempt is
type Effect =
| Log of string
| Sleep of int
type Computation<'t> = Computation of Lazy<'t * Effect list>
let private bind (u : 'u, effs : Effect list)
(f : 'u -> 'v * Effect list)
: ('v * Effect list) =
let v, newEffs = f u
let allEffects = List.append effs newEffs
v, allEffects
type ComputeBuilder() =
member this.Zero() = lazy ((), [])
member this.Return(x) = x, []
member this.ReturnFrom(Computation f) = f.Force()
member this.Bind(x, f) = bind x f
member this.Delay(funcToDelay) = funcToDelay
member this.Run(funcToRun) = Computation (lazy funcToRun())
let compute = new ComputeBuilder()
let log msg = (), [Log msg]
let sleep ms = (), [Sleep ms]
let run (Computation x) = x.Force()
...but the compiler complains about the let! lines in the following code:
let x =
compute {
let! a = add 10 20
let! b = add 11 2000
return a + b
}
Error FS0001: This expression was expected to have type
'a * Effect list
but here has type
Computation<'b> (FS0001)
Any suggestions?
The main thing that is not right with your definition is that some of the members of the computation builder use your Computation<'T> type and some of the other members use directly a pair of value and list of effects.
To make it type check, you need to be consistent. The following version uses Computation<'T> everywhere - have a look at the type signature of Bind, for example:
let private bind (Computation c) f : Computation<_> =
Computation(Lazy.Create(fun () ->
let u, effs = c.Value
let (Computation(c2)) = f u
let v, newEffs = c2.Value
let allEffects = List.append effs newEffs
v, allEffects))
type ComputeBuilder() =
member this.Zero() = Computation(lazy ((), []))
member this.Return(x) = Computation(lazy (x, []))
member this.ReturnFrom(c) = c
member this.Bind(x, f) = bind x f
member this.Delay(funcToDelay:_ -> Computation<_>) =
Computation(Lazy.Create(fun () ->
let (Computation(r)) = funcToDelay()
r.Value))

How do you access items in a tuple that is a discriminated union?

Say I declare a type like so:
type Kvp = Kvp of string * int
And I create an instance of it
let inst = Kvp("twelve", 12)
How do I get the first and second values from inst? Fst and snd don't work:
fst inst;;
stdin(81,5): error FS0001: This expression was expected to have type
'a * 'b
but here has type
Kvp
As s952163 mentioned, pattern matching is what you want. However, the nice syntax is this
type Kvp = Kvp of string * int
let inst = Kvp("twelve", 12)
let (Kvp (str,i)) = inst
// val str : string = "twelve"
// val i : int = 12
You can also use _ to discard what you don't want:
let (Kvp (str,_)) = inst
Here's the F# for fun and profit page on Single Case DUs
Because a DU is not a tuple you get that error. But you can pattern match on a DU:
type Kvp = Kvp of string * int
let inst = Kvp("twelve", 12)
let (a,b) =
match inst with
| Kvp(a,b) -> (a,b)
//val b : int = 12
//val a : string = "twelve"
And somewhere in the middle of F# Fun there is an example of a matcher functions.

Statically resolved types member constraints fail to recognize augmentations of system types

On my quest to get better at F# and gain a better understanding on how Suave.io works, I've been attempting to create some reusable functions/operators for composing functions. I understand that Suave actually implements its >=> operator to work specifically for async option, but I thought I would be fun to try and generalize it.
The code below is inspired by too many sources to credit, and it works well for types I define myself, but I can't make it work for system types. Even though the type augmentations of Nullable and Option compiles fine, they aren't recognized as matching the member constraint in the bind function.
When I failed to make it work for Option, I had hoped that it might be due to Option being special in F#, which is why I tried with Nullable, but sadly, no cigar.
The relevant errors and output from fsi is in the code below in the comment.
Any help would be appreciated.
Thanks,
John
open System
let inline bind (f : ^f) (v : ^v) =
(^v : (static member doBind : ^f * ^v -> ^r )(f, v))
// I'd prefer not having to use a tuple in doBind, but I've
// been unable to make multi arg member constraint work
let inline (>=>) f g = f >> (bind g)
// Example with Result
type public Result<'a,'b> =
| Success of 'a
| Error of 'b
type public Result<'a,'b> with
static member inline public doBind (f, v) =
match v with
| Success s -> f s
| Error e -> Error e
let rF a = if a > 0 then Success a else Error "less than 0"
let rG a = if a < 10 then Success a else Error "greater than 9"
let rFG = rF >=> rG
// val rFG : (int -> Result<int,string>)
//> rFG 0;;
//val it : Result<int,string> = Error "less than 0"
//> rFG 1;;
//val it : Result<int,string> = Success 1
//> rFG 10;;
//val it : Result<int,string> = Error "greater than 9"
//> rFG 9;;
//val it : Result<int,string> = Success 9
// So it works as expected for Result
// Example with Nullable
type Nullable<'T when 'T: (new : unit -> 'T) and 'T: struct and 'T:> ValueType> with
static member inline public doBind (f, v: Nullable<'T>) =
if v.HasValue then f v.Value else Nullable()
let nF a = if a > 0 then Nullable a else Nullable()
let nG a = if a < 10 then Nullable a else Nullable()
let nFG = nF >=> nG
// error FS0001: The type 'Nullable<int>' does not support the operator 'doBind'
type Core.Option<'T> with
static member inline doBind (f, v) =
match v with
| Some s -> f s
| None -> None
let oF a = if a > 0 then Some a else None
let oG a = if a < 10 then Some a else None
let oFG = oF >=> oG
// error FS0001: The type 'int option' does not support the operator 'doBind'
Why extension methods are not taken into account in static member constraints is a question that has been asked many times and surely it will continue being asked until that feature is implemented in the F# compiler.
See this related question with a link to other related questions and a link to a detailed explanation of what has to be done in the F# compiler in order to support this feature.
Now for your specific case the workaround mentioned there solves you issue and it's already implemented in FsControl.
Here's the code:
#nowarn "3186"
#r "FsControl.dll"
open FsControl.Operators
// Example with Result
type public Result<'a,'b> =
| Success of 'a
| Error of 'b
type public Result<'a,'b> with
static member Return v = Success v
static member Bind (v, f) =
match v with
| Success s -> f s
| Error e -> Error e
let rF a = if a > 0 then Success a else Error "less than 0"
let rG a = if a < 10 then Success a else Error "greater than 9"
let rFG = rF >=> rG
// val rFG : (int -> Result<int,string>)
rFG 0
//val it : Result<int,string> = Error "less than 0"
rFG 1
//val it : Result<int,string> = Success 1
rFG 10
//val it : Result<int,string> = Error "greater than 9"
rFG 9
//val it : Result<int,string> = Success 9
// So it works as expected for Result
// Example with Option
let oF a = if a > 0 then Some a else None
// val oF : a:int -> int option
let oG a = if a < 10 then Some a else None
// val oG : a:int -> int option
let oFG = oF >=> oG
// val oFG : (int -> int option)
oFG 0
// val it : int option = None
oFG 1
// val it : int option = Some 1
Anyway I would recommend using existing Choice instead of Success/Error or implementing Success on top of Choice in your case it would be like this:
type Result<'a, 'b> = Choice<'a, 'b>
let Success x :Result<'a, 'b> = Choice1Of2 x
let Error x :Result<'a, 'b> = Choice2Of2 x
let (|Success|Error|) = function Choice1Of2 x -> Success x | Choice2Of2 x -> Error x
And then you can run your examples without writing any bind or return.
You might wonder why there is no example for Nullable, well that's simply because Nullable is not a monad, it only works on value types and a function is not a value type so better stick to Option for the same functionality.

how can I parameterize a F# class

The class below is a wrapper around an async MailboxProcessor that exposes
a few operations to C# assemblies. However, I don't want just a few
Map<string,int>
instances, I need several different Map<'K,'V> instances where 'K and 'V vary.
I hope I don't need a functor for that (it probably doesn't exist in F#).
module Flib.AsyncEvents
open System.Collections.Generic
type KVcoll = Map<string,int>
type Msg = Request of string * int option | Fetch of AsyncReplyChannel<KVcoll> | Clear
#nowarn "40"
type myAgent () = class
let dictAgent = MailboxProcessor.Start(fun inbox->
let dict = ref Map.empty
let rec loop = async {
let! msg = inbox.Receive()
match msg with
| Request (key, Some value) -> dict := Map.add key value !dict
| Request (key, None) -> dict := Map.remove key !dict
| Fetch(reply) -> reply.Reply(!dict)
| Clear -> dict := Map.empty
return! loop
}
loop)
member this.add(key, value) = dictAgent.Post (Request (key, Some value))
member this.del(key) = dictAgent.Post (Request(key, None))
member this.fetch() = dictAgent.PostAndReply((fun reply -> Fetch(reply)), timeout = 9000)
member this.lookup(key) = try 0, Map.find key (this.fetch()) // success
with | :? KeyNotFoundException -> -1, 0 // failure
member this.size() = this.fetch().Count
member this.clear() = dictAgent.Post (Clear)
member this.print() =
this.fetch() |> Map.iter (fun k v -> printfn "%s => %d" k v)
printfn "done"
end
By the way, this is prototype quality code, clearly not as good as it can be.
I'm not sure I understand the question fully, but if you want to create a type that can be used with different types of values, you can define the class as generic:
type Msg<'K, 'V when 'K : comparison> =
| Request of 'K * 'V option
| Fetch of AsyncReplyChannel<Map<'K, 'V>>
| Clear
type MyAgent<'K, 'V when 'K : comparison> () = class
let dictAgent = MailboxProcessor.Start(fun inbox->
let dict : Map<'K, 'V> ref = ref Map.empty
let rec loop = async {
// (same as before)
}
loop)
To make this work, you'll need to avoid code that restricts the type of keys and values to a particular type. In you case lookup was returning 0 as the default value and print was expecting strings. So you can replace those with something like:
member this.lookup(key) = Map.tryFind key (this.fetch())
member this.print() =
this.fetch() |> Map.iter (fun k v -> printfn "%A => %A" k v)
printfn "done"

Wrangling TryWith in Computation expressions

(Having failed to 'grok' FParsec, I followed the advice I read somewhere and started trying to write a little parser myself. Somehow I spotted what looked like a chance to try and monadify it, and now I have N problems...)
This is my 'Result' type (simplified)
type Result<'a> =
| Success of 'a
| Failure of string
Here's the computation expression builder
type ResultBuilder() =
member m.Return a = Success(a)
member m.Bind(r,fn) =
match r with
| Success(a) -> fn a
| Failure(m) -> Failure(m)
In this first example, everything works (compiles) as expected:
module Parser =
let res = ResultBuilder()
let Combine p1 p2 fn =
fun a -> res { let! x = p1 a
let! y = p2 a
return fn(x,y) }
My problem is here: I'd like to be able to catch any failure in the 'combining' function and return a failure, but it says that I should define a 'Zero'.
let Combine2 p1 p2 fn =
fun a -> res { let! x = p1 a
let! y = p2 a
try
return fn(x,y)
with
| ex -> Failure(ex.Message) }
Having no idea what I should return in a Zero, I just threw in member m.Zero() = Failure("hello world"), and it now says I need TryWith.
So:
member m.TryWith(r,fn) =
try
r()
with
| ex -> fn ex
And now it wants Delay, so member m.Delay f = (fun () -> f()).
At which point it says (on the ex -> Failure), This expression should have type 'unit', but has type 'Result<'a>', and I throw up my arms and turn to you guys...
Link for playing: http://dotnetfiddle.net/Ho1sGS
The with block should also return a result from the computation expression. Since you want to return Result.Failure you need to define the member m.ReturnFrom a = a and use it to return the Failure from the with block. In the try block you should also specify that fn returns Success if it doesn't throw.
let Combine2 p1 p2 fn =
fun a -> res { let! x = p1 a
let! y = p2 a
return!
try
Success(fn(x,y))
with
| ex -> Failure(ex.Message)
}
Update:
The original implementation was showing a warning, not an error. The expression in the with block was not used since you returned from the try block, so you could simply add |> ignore. In that case if fn throws then the return value is m.Zero() and the only difference is that you would get "hello world" instead of ex.Message. Illustrated with an example below. Full script here: http://dotnetfiddle.net/mFbeZg
Original implementation with |> ignore to mute the warning:
let Combine3 p1 p2 fn =
fun a -> res { let! x = p1 a
let! y = p2 a
try
return fn(x,y)
with
| ex -> Failure(ex.Message) |> ignore // no warning
}
Run it:
let comb2 a =
let p1' x = Success(x)
let p2' y = Success(y)
let fn' (x,y) = 1/0 // div by zero
let func = Parser.Combine2 p1' p2' fn' a
func()
let comb3 a =
let p1' x = Success(x)
let p2' y = Success(y)
let fn' (x,y) = 1/0 // div by zero
let func = Parser.Combine3 p1' p2' fn' a
func()
let test2 = comb2 1
let test3 = comb3 1
Result:
val test2 : Result<int> = Failure "Attempted to divide by zero."
val test3 : Result<int> = Failure "hello world"
If you want to support try ... with inside a computation builder, you need to add TryWith (as you tried) as well as a few other members including Delay and Run (depending on how you want to implement Delay). In order to be able to return failure, you also need to support return! by adding ReturnFrom:
type ResultBuilder() =
member m.Return a = Success(a)
member m.Bind(r,fn) =
match r with
| Success(a) -> fn a
| Failure(m) -> Failure(m)
member m.TryWith(r,fn) =
try r() with ex -> fn ex
member m.Delay(f) = f
member m.Run(f) = f()
member m.ReturnFrom(r) = r
Now you can do the following:
let Combine2 p1 p2 fn = fun a -> res {
let! x = p1 a
let! y = p2 a
try
return fn(x,y)
with ex ->
return! Failure(ex.Message) }
The trick is that the normal branch uses just return (representing success), but the exception handler uses return! to return an explicitly created result using Failure.
That said, if you are interested in parsers, then you need to use a different type - what you are describing here is more like the option (or Maybe) monad. To implement parser combinators you need a type that represents a parser rather than result of a parser. See for example this article.

Resources