Skip to content

Commit

Permalink
Use FsToolkit.ErrorHandling and reorganise modules (#5)
Browse files Browse the repository at this point in the history
* Add rider files to gitignore

* Increment version number

* Reorganise modules

* Remove task functions included in FsT
  • Loading branch information
michaelwinch authored Nov 14, 2024
1 parent 274fb6c commit 1994665
Show file tree
Hide file tree
Showing 26 changed files with 419 additions and 407 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
- master

env:
publish_version: 0.0.${{ github.run_number }}
publish_version: 1.0.${{ github.run_number }}

jobs:
build:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ obj/
release.cmd
release.sh
.ionide/
.idea/
_public
build/
out/
2 changes: 2 additions & 0 deletions paket.dependencies
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ storage: none
framework: auto-detect

nuget FSharp.Core
nuget FsToolkit.ErrorHandling
nuget FsToolkit.ErrorHandling.TaskResult
nuget Expecto
nuget FsCheck
nuget Expecto.FsCheck
Expand Down
4 changes: 4 additions & 0 deletions paket.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ NUGET
FsCheck (2.16.5)
FSharp.Core (>= 4.2.3)
FSharp.Core (6.0.6)
FsToolkit.ErrorHandling (3.2)
FSharp.Core (>= 6.0.3)
FsToolkit.ErrorHandling.TaskResult (3.2)
FsToolkit.ErrorHandling (>= 3.2)
Mono.Cecil (0.11.4)

GROUP Docs
Expand Down
14 changes: 14 additions & 0 deletions src/AsyncWriterResult/Async.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace AsyncWriterResult

[<RequireQualifiedAccess>]
module Async =

let zip c1 c2 =
async {
let! ct = Async.CancellationToken
let x = Async.StartImmediateAsTask (c1, cancellationToken = ct)
let y = Async.StartImmediateAsTask (c2, cancellationToken = ct)
let! x' = Async.AwaitTask x
let! y' = Async.AwaitTask y
return x', y'
}
11 changes: 11 additions & 0 deletions src/AsyncWriterResult/AsyncWriter.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace AsyncWriterResult

open FsToolkit.ErrorHandling

[<RequireQualifiedAccess>]
module AsyncWriter =

let retn a = Writer.retn a |> Async.retn

let map f = f |> Writer.map |> Async.map

81 changes: 81 additions & 0 deletions src/AsyncWriterResult/AsyncWriterResult.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
namespace AsyncWriterResult

open FsToolkit.ErrorHandling
open AsyncWriterResult

type AsyncWriterResult<'ok, 'error, 'log> = Async<Writer<'log list, Result<'ok, 'error>>>

[<RequireQualifiedAccess>]
module AsyncWriterResult =

let retn x = x |> WriterResult.retn |> Async.retn

let map f = f |> WriterResult.map |> Async.map

// let bind (f:'a -> Async<Writer<'b list, Result<'c,'d>>>) (m:Async<Writer<'b list, Result<'a,'d>>>) : Async<Writer<'b list, Result<'c,'d>>> = async {
let bind f m =
async {
let! w = m
let r, logs1 = Writer.run w

match r with
| Ok a ->
let! ww = f a
let b, logs2 = Writer.run ww
return Writer <| fun () -> b, logs1 @ logs2
| Error e -> return Writer <| fun () -> Error e, logs1
}

let apply f m =
async {
let! uf = f
let! um = m
let r1, logs1 = Writer.run uf
let r2, logs2 = Writer.run um

match r1, r2 with
| Ok g, Ok h -> return Writer <| fun () -> Ok(g h), logs1 @ logs2
| Error e1, _ -> return Writer <| fun () -> Error e1, logs1 @ logs2
| _, Error e2 -> return Writer <| fun () -> Error e2, logs1 @ logs2
}

let write log =
async { return Writer(fun () -> Result.retn (), [ log ]) }

let mapError e m =
async {
let! w = m
let r, logs = Writer.run w
return Writer <| fun () -> Result.mapError e r, logs
}

let private errMsg m (e: exn) = Error(sprintf "%s: %s" m e.Message)

let tryTo desc f =
f
>> Async.Catch
>> Async.map (function
| Choice1Of2 a -> Ok a
| Choice2Of2 e when (e :? System.AggregateException) -> errMsg desc e.InnerException
| Choice2Of2 e -> errMsg desc e)
>> Async.map Writer.retn

let traverseResultM f list =

let (>>=) x f = bind f x

let cons head tail = head :: tail

let folder head tail =
f head
>>= (fun h -> tail >>= (fun t -> retn (cons h t)))

List.foldBack folder list (retn [])

let collect list =
Async.Parallel list
|> Async.map (List.ofArray >> WriterResult.collect)

let zip left right =
Async.zip left right
|> Async.map (fun (r1, r2) -> WriterResult.zip r1 r2)
17 changes: 16 additions & 1 deletion src/AsyncWriterResult/AsyncWriterResult.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,23 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<Compile Include="Library.fs" />
<Compile Include="Result.fs" />
<Compile Include="Async.fs" />
<Compile Include="Task.fs" />
<Compile Include="Writer.fs" />
<Compile Include="WriterCE.fs" />
<Compile Include="WriterOp.fs" />
<Compile Include="AsyncWriter.fs" />
<Compile Include="TaskWriter.fs" />
<Compile Include="WriterResult.fs" />
<Compile Include="WriterResultCE.fs" />
<Compile Include="WriterResultOp.fs" />
<Compile Include="AsyncWriterResult.fs" />
<Compile Include="AsyncWriterResultCE.fs" />
<Compile Include="AsyncWriterResultOp.fs" />
<Compile Include="TaskWriterResult.fs" />
<Compile Include="TaskWriterResultCE.fs" />
<Compile Include="TaskWriterResultOp.fs" />
</ItemGroup>
<Import Project="..\..\.paket\Paket.Restore.targets" />
</Project>
35 changes: 35 additions & 0 deletions src/AsyncWriterResult/AsyncWriterResultCE.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
namespace AsyncWriterResult

open FsToolkit.ErrorHandling
open System.Threading.Tasks

[<AutoOpen>]
module AsyncWriterResultCE =
type AsyncWriterResultBuilder() =
member __.Return(x) = AsyncWriterResult.retn x
member __.ReturnFrom(m: Async<Writer<'w, Result<'a, 'b>>>) = m
member __.Bind(m, f) = AsyncWriterResult.bind f m
member __.Zero() = __.Return()
member __.BindReturn(x, f) = AsyncWriterResult.map f x
member __.MergeSources(x, y) = AsyncWriterResult.zip x y
member __.Source(x: Async<Writer<'w, Result<'a, 'b>>>) = x
member __.Source(x: Task<Writer<'w, Result<'a, 'b>>>) = x |> Async.AwaitTask

let asyncWriterResult = AsyncWriterResultBuilder()

[<AutoOpen>]
module AsyncWriterResultBuilderExtensions =
type AsyncWriterResultBuilder with
member __.Source(x: Result<'a, 'b>) = x |> AsyncWriter.retn
member __.Source(x: Writer<'w, 't>) = x |> Writer.map Ok |> Async.retn
member __.Source(x: Async<'t>) = x |> Async.map WriterResult.retn
member __.Source(x: Task<'t>) = x |> Async.AwaitTask |> Async.map WriterResult.retn

[<AutoOpen>]
module AsyncWriterResultBuilderExtensionsHighPriority =
type AsyncWriterResultBuilder with
member __.Source(x: Writer<'w, Result<'a, 'b>>) = x |> Async.retn
member __.Source(x: Async<Result<'a, 'b>>) = x |> Async.map Writer.retn
member __.Source(x: Async<Writer<'w, 't>>) = x |> AsyncWriter.map Result.retn
member __.Source(x: Task<Result<'a, 'b>>) = x |> Async.AwaitTask |> Async.map Writer.retn
member __.Source(x: Task<Writer<'w, 't>>) = x |> Async.AwaitTask |> AsyncWriter.map Result.retn
15 changes: 15 additions & 0 deletions src/AsyncWriterResult/AsyncWriterResultOp.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace AsyncWriterResult.Operator.AsyncWriterResult

open AsyncWriterResult

/// Operators for working with the AsyncWriterResult type
[<AutoOpen>]
module AsyncWriterResult =
/// AsyncWriterResult.map
let (<!>) f x = AsyncWriterResult.map f x

/// AsyncWriterResult.apply
let (<*>) f x = AsyncWriterResult.apply f x

/// AsyncWriterResult.bind
let (>>=) x f = AsyncWriterResult.bind f x
Loading

0 comments on commit 1994665

Please sign in to comment.