Last active
November 4, 2020 00:14
-
-
Save sanisoclem/744f4d3544a738976c5cbb09faa45e50 to your computer and use it in GitHub Desktop.
F# Lifesavers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://stackoverflow.com/a/54714775/3004147 | |
module Result = | |
open Result | |
let rtn = Ok | |
let toOption r = r |> function Ok v -> Some v | _ -> None | |
let defaultWith f r = r |> function Ok v -> v | Error e -> f e | |
let defaultValue d r = r |> function Ok v -> v | Error _ -> d | |
let failIfTrue m v = if v then m |> Error else Ok () | |
let failIfFalse m v = if not v then m |> Error else Ok () | |
let iter fE f r = r |> map f |> defaultWith fE : unit | |
let get r = r |> defaultWith (string >> failwith) | |
let ofOption f vO = vO |> Option.map Ok |> Option.defaultWith (f >> Error) | |
let insertO vRO = vRO |> Option.map(map Some) |> Option.defaultWith(fun () -> Ok None) | |
let absorbO f vOR = vOR |> bind (ofOption f) | |
module Async = | |
let inline rtn v = async.Return v | |
let inline bind f vA = async.Bind( vA, f) | |
let inline map f = bind (f >> rtn) | |
let inline iterS (f: 'a->unit) = map f >> Async.RunSynchronously | |
let inline iterA f = map f >> Async.Start | |
type AsyncResult<'v, 'm> = Async<Result<'v, 'm>> | |
module AsyncResult = | |
let mapError fE v = v |> Async.map (Result.mapError fE) | |
let rtn v = async.Return(Ok v ) | |
let rtnR vR = async.Return vR | |
let iterS fE f vRA = Async.iterS (Result.iter fE f) vRA | |
let iterA fE f vRA = Async.iterA (Result.iter fE f) vRA | |
let bind fRA vRA = async { | |
let! vR = vRA | |
match vR with | |
| Ok v -> return! fRA v | |
| Error m -> return Error m | |
} | |
let inline map f m = bind (f >> rtn) m | |
let rec whileLoop cond fRA = | |
if cond () | |
then fRA () |> bind (fun () -> whileLoop cond fRA) | |
else rtn () | |
let (>>=) v f = bind f v | |
let rec traverseSeq f sq = let folder head tail = f head >>= (fun h -> tail >>= (fun t -> List.Cons(h,t) |> rtn)) | |
Array.foldBack folder (Seq.toArray sq) (rtn List.empty) |> map Seq.ofList | |
let inline sequenceSeq sq = traverseSeq id sq | |
let insertO vRAO = vRAO |> Option.map(map Some) |> Option.defaultWith(fun () -> rtn None) | |
let insertR ( vRAR:Result<_,_>) = vRAR |> function | Error m -> rtn (Error m) | Ok v -> map Ok v | |
let absorbR vRRA = vRRA |> Async.map (Result.bind id) | |
let absorbO f vORA = vORA |> Async.map (Result.absorbO f) | |
type AsyncResultBuilder() = | |
member __.ReturnFrom vRA : Async<Result<'v , 'm>> = vRA | |
member __.ReturnFrom vR : Async<Result<'v , 'm>> = AsyncResult.rtnR vR | |
member __.Return v : Async<Result<'v , 'm>> = AsyncResult.rtn v | |
member __.Zero () : Async<Result<unit, 'm>> = AsyncResult.rtn () | |
member __.Bind (vRA, fRA) : Async<Result<'b , 'm>> = AsyncResult.bind fRA vRA | |
member __.Bind (vR , fRA) : Async<Result<'b , 'm>> = AsyncResult.bind fRA (vR |> AsyncResult.rtnR) | |
member __.Combine (vRA, fRA) : Async<Result<'b , 'm>> = AsyncResult.bind fRA vRA | |
member __.Combine (vR , fRA) : Async<Result<'b , 'm>> = AsyncResult.bind fRA (vR |> AsyncResult.rtnR) | |
member __.Delay fRA = fRA | |
member __.Run fRA = AsyncResult.rtn () |> AsyncResult.bind fRA | |
member __.TryWith (fRA , hnd) : Async<Result<'a , 'm>> = async { try return! fRA() with e -> return! hnd e } | |
member __.TryFinally(fRA , fn ) : Async<Result<'a , 'm>> = async { try return! fRA() finally fn () } | |
member __.Using(resource , fRA) : Async<Result<'a , 'm>> = async.Using(resource, fRA) | |
member __.While (guard , fRA) : Async<Result<unit, 'a>> = AsyncResult.whileLoop guard fRA | |
member th.For (s: 'a seq, fRA) : Async<Result<unit, 'b>> = th.Using(s.GetEnumerator (), fun enum -> | |
th.While(enum.MoveNext, | |
th.Delay(fun () -> fRA enum.Current))) | |
let asyncResult = AsyncResultBuilder() | |
[<AutoOpen>] | |
module Extensions = | |
type AsyncResultBuilder with | |
member __.ReturnFrom (vA: Async<'a> ) : Async<Result<'a, 'b>> = Async.map Ok vA | |
member __.Bind (vA: Async<'a>, fRA) : Async<Result<'b, 'c>> = AsyncResult.bind fRA (Async.map Ok vA) | |
member __.Combine (vA: Async<'a>, fRA) : Async<Result<'b, 'c>> = AsyncResult.bind fRA (Async.map Ok vA) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment