Giter Site home page Giter Site logo

chessie's Introduction

chessie's People

Contributors

chrsteinert avatar cumpsd avatar daleardi avatar dnauck avatar edhzsz avatar enricosada avatar forki avatar fsprojectsgit avatar kellerd avatar matthid avatar mavnn avatar mexx avatar pblasucci avatar sergey-tihon avatar theimowski avatar theor avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

chessie's Issues

Error list for combined validation failures

I'm interested how to get an error list of combined validation failures.
In ROP example by Scott he is using plus or &&&.

I assume in Chessie this is apply or <*>, but I'm not sure how to use it.
I didn't see any example of using it, and no test on this function.
Is there a possibility for somebody to show example of using (as in your docs combinedValidation) but result to be, all errors that happened in all validation combined together, because with bind >> only first error is returned?

Thanks.

Add mergeErrors and collectErrors to Trial module

Feature

This is not a problem but a feature I'm proposing. I don't know whether it can be easily reproduced with current functionality. I could make a PR if you want me to, but I wanted to ask here before going forward.

I have the following situation: I want to be able to collect a number of validation results in the form of Result<unit, ‘error> and obtain a condensed validation result of the same type.

So I would like to be able to do:

let result = trial {
    let validations = [ validate1; validate2; validate3; … ]
    return! Validations |> collectErrors
}

Where:

module Chessie.ErrorHandling.Trial
...
let mergeErrors result1 result2 =
    match result1, result2 with
    | Ok ((), errors1), Ok ((), errors2) ->
        Ok ((), errors1 @ errors2)
    | Ok ((), errors1), Bad (errors2)
    | Bad (errors1), Ok ((), errors2)
    | Bad (errors1), Bad (errors2) ->
        Bad (errors1 @ errors2)

let collectErrors = 
    Seq.reduce mergeErrors

It could be further generalized for collecting all results and errors. For example:

let mergeResults reducer result1 result2 =
    match result1, result2 with
    | Ok (r1, errors1), Ok (r2, errors2) ->
        Ok (reducer r1 r2, errors1 @ errors2)
    | Ok (_, errors1), Bad (errors2)
    | Bad (errors1), Ok (_, errors2)
    | Bad (errors1), Bad (errors2) ->
        Bad (errors1 @ errors2)

let collectResults reducer = 
    Seq.reduce (mergeResults reducer) 

Please direct me on the right direction if this does not make any sense, or indicate if you want me to start a PR.

Thanks

Q: Trial.returnOrFail method name

Before raising my grasp (and I've still a lot to understand and learn) of monads, I was always confused by return monadic operation.

For what I understand now the return operation (called sometime unit if I'm not wrong) inject a value into the monadic abstraction.
In fact, in Haskell the Control.Monad type class defines return with this signature return :: a -> m a.
In FSharp that lacks HKT:

type Maybe = Just x | Nothing
module Maybe =
  return x = Just x
  // ...

we must define everything for each specific monad. Unless creating a strange convoluted and not idiomatic implementations, I guess...

So also if returnOrFail sense is clear it's name doesn't clash with this concept? It's not better something like getOrFail? (E.g.: I'm agree to a more domain specific return like Succeed and FailWith.

I know that computations expressions have a ReturnFrom for allowing a wrapped value escape the monad, and in fact now I found it confusing...

I'm not here to criticize, just to hear thoughs and learn more about the subject. If I wouldn't like this library, I'd never ported it to C# for direct source inclusion as annunced in issue #25 (library that still need refinements and comments...).

My best regards,
Giacomo

Improve styling in header

Description

It is not showing properly the forking repo elements and links

image

Repro steps

Please provide the steps required to reproduce the problem

  1. Step A

  2. Step B

It should Represent very nicely to fork this repository to beginners

Please provide a description of the behavior you expect.

Actual behavior

Please provide a description of the actual behavior you observe.

Known workarounds

Please provide a description of any known workarounds.

Related information

  • Operating system
  • Branch
  • .NET Runtime, CoreCLR or Mono Version
  • Performance information, links to performance testing scripts

Messages lost on apply

Currently you have the following:

    let inline apply wrappedFunction result = 
        match wrappedFunction, result with
        | Ok(f, msgs1), Ok(x, msgs2) -> Ok(f x, msgs1 @ msgs2)
        | Fail errs, Ok(_, msgs) -> Fail(errs)
        | Ok(_, msgs), Fail errs -> Fail(errs)
        | Fail errs1, Fail errs2 -> Fail(errs1)

When looking at Scott his ROP implementation he has:

let applyR f result =
    match f,result with
    | Success (f,msgs1), Success (x,msgs2) -> 
        (f x, msgs1@msgs2) |> Success 
    | Failure errs, Success (_,msgs) 
    | Success (_,msgs), Failure errs -> 
        errs @ msgs |> Failure
    | Failure errs1, Failure errs2 -> 
        errs1 @ errs2 |> Failure

Could we change it in Chessie to either one of these two:

Option 1

This is identical to Scott's version

    let inline apply wrappedFunction result = 
        match wrappedFunction, result with
        | Ok(f, msgs1), Ok(x, msgs2) -> Ok(f x, msgs1 @ msgs2)
        | Fail errs, Ok(_, msgs)
        | Ok(_, msgs), Fail errs -> Fail(errs @ msgs)
        | Fail errs1, Fail errs2 -> Fail(errs1 @ errs2)

Option 2

On fail, don't take the Ok messages along

    let inline apply wrappedFunction result = 
        match wrappedFunction, result with
        | Ok(f, msgs1), Ok(x, msgs2) -> Ok(f x, msgs1 @ msgs2)
        | Fail errs, Ok(_, msgs)
        | Ok(_, msgs), Fail errs -> Fail(errs)
        | Fail errs1, Fail errs2 -> Fail(errs1 @ errs2)

Should apply <*> Concat All Messages?

When looking at the code for apply, it seems to only concat all the messages when either both results are Ok or both are Bad. Should it concat all the message regardless?

| Bad errs, Ok(_, msgs) -> Bad(errs)
| Ok(_, msgs), Bad errs -> Bad(errs)

I am trying to return a list of failure messages when using apply

createThing <!> firstOrFail <*> secondOrFail <*> thirdOrFail

And instead of giving me all the messages it just gives me the first after a failure.
If I rewrite the middle two cases of apply I appear to get what I am after.

So is this a bug, enhancement, or am I actually asking for different function other then apply, like applyWithAllMessage <*+>?

    /// If the wrapped function is a success and the given result is a success the function is applied on the value. 
    /// Otherwise the exisiting error messages are propagated.
    let inline apply wrappedFunction result = 
        match wrappedFunction, result with
        | Ok(f, msgs1), Ok(x, msgs2) -> Ok(f x, msgs1 @ msgs2)
        | Bad errs, Ok(_, msgs) -> Bad(errs @ msgs)
        | Ok(_, msgs), Bad errs -> Bad(errs @ msgs)
        | Bad errs1, Bad errs2 -> Bad(errs1 @ errs2)

mergeMessages uses inconsistent ordering

Description

mergeMessages appends messages for error but prepends them for success

Expected behavior

mergeMessages should be consistent; IMHO it should always append them, as this is merging messages into an existing Result stream.

    let inline mergeMessages msgs result = 
        let inline fSuccess (x, msgs2) = Ok(x, msgs @ msgs2) // prepends
        let inline fFailure errs = Bad(errs @ msgs) // appends
        either fSuccess fFailure result

I just came across this library =)

I have a gist that I include in most of my FSharp projects. I wanted to ask if the maintainer of this project is willing to expand the AsyncResult type to include utility methods like Trial has (See gist link). I got most if not all the code from Scott Wlaschin after I read his DDD with FSharp book.

Just a thought =)

Added support for C# source inclusion

Hi there,
thanks for sharing this wonderful library. I've also appreciated C# extension methods, but I think (personal opinion) that some C# developer could prefer including Result<TSuccess,TMessage> directly at source level (without referencing an assembly).

For this reason I've ported your work to C# native implementation. I've skipped async part, since is mainly for computation expressions and in C# Task<Result<TSucc,TMsg>> will suffice.

This is the link to the project: https://github.com/gsscoder/railwaysharp. (I've also included test code from your project).

Feel free to do with it whatever you want...

Regards,
Giacomo

LINQ extension method `SelectMany` yields duplicated messages

The LINQ extension method SelectMany yields duplicated messages when the LINQ query syntax is used as this test shows:

[Test]
public void Test()
{
    Func<Result<string, string>> f = () => 
        from a in Result<string, string>.FailWith("fail")
        from b in Result<string, string>.Succeed("succeed")
        from c in Result<string, string>.Succeed("succeed")
        select a + b + c;

    f().Match(
        ifSuccess: (s, list) => Assert.Fail(),
        ifFailure: list => Assert.That(list, Is.EquivalentTo(new[] { "fail" })));
}

The test fails with this message:

Expected: equivalent to < "fail" >  But was:  < "fail", "fail", "fail", "fail" >

Better map operator

To compose results in a nice way, more operators would be useful.
The one I always end up implementing is a flipped map/(<!>):

// fromProcess returns a Result<string,ProcessMessage>

// with <!> operator
let devices' () =
    Process.exec "." Adb.adb "devices"
    |> fromProcess
    |> (<!>) Strings.toLines
    |> (<!>) (Seq.choose device)
    |> (<!>) (Seq.map ((flip>>uncurry) model))

// with flipped <!>
let inline (<**>) x y = (flip (<!>)) x y

let devices () =
    Process.exec "." Adb.adb "devices"
    |> fromProcess
    <**> Strings.toLines
    <**> (Seq.choose device)
    <**> (Seq.map ((flip>>uncurry) model))

Use or not of ROP terminology

Because I think this is a better forum than twitter!

@tpetricek do you mind explaining your opposition to using ROP based names? I'm not sure I'm seeing the issue yet, especially if we have a two sentence byline of "this is an either monad under the hood" somewhere.

It feels like it throws away a lot of Scott's good work on explaining things in nice easy to understand language.

Fail active recognizer shadows Fail union case

The Fail active recognizer introduced in #15 by @pblasucci shadows the Fail union case.
It actually introduces "incomplete pattern matches on this expression" compiler warnings for code like

match result with
| Ok (x, msgs) -> ...
| Fail (msgs) -> ...

Prior to this change the match was complete.
Fortunately the change only confuses the compiler and do not change the behavior of the pattern match.

We should require qualified access on one of the two constructs or rename one of them to avoid the name clash.

Nicer static methods for C#

To create a Result in Chessie, you have to explicitly specify both generic types e.g.: -

Result<MyMessage, string>.Succeed(myMessage)

This could be simplified by having static methods on a non-generic Result class e.g.

Result.Succeed<string>(myMessage)

Handling Async bind

Hi,
First of all great work, it is much appreciated.
One area I have struggled with using ROP is making bind work in an Async call/pipeline. I have kludged an Async bind like this (excuse RopResult instead of Result)
image

Any suggestions on an Async approach using Chessie would be most appreciated.

Support .NET Core

support .NET Core

  • 1) build with .NET CLI and project.json the .NET core
  • 2) add built netcore assemblies to package

i added the issue because i am working 1)

We need docs.

I started by adding XML docs. Would like to see more docs and links to videos and articles.
Also samples (maybe taken from Paket).

Fsharp.Core MissingMethodException when using Chessie from Paket.Core

Hello, I have a weird issue on chessie when using paket.core

Description

Fsharp.Core MissingMethodException when using Paket.Core with latest version of Chessie

Repro steps

Install Paket.Core in a VSIX solution.
Try using the FindOutdated or Update command from the library --> Fail with MissingMethodException

Known workarounds

Update the target framework for Chessie F# project from 4.0 to 4.5
(I tried this using paket.local for chessie)
No more exception.

Maybe a upgrade to framework 4.5 could be done on the main project, knowing that Chessie.CSharp.Test and Chessie.Tests are already on 4.5

Thanks,
Thomas

unexpected usage of Trial.either

Description

I want to use Chessie for error handling, but Trial.either does not make sense to me.

Repro steps

Try to compile this:

open System
open Chessie.ErrorHandling

type Error =
  | InvalidEmail of string
  | DatabaseError of Exception

let validateEmail (email:string) =
  if email.Contains("@")
  then ok email
  else fail (InvalidEmail "@ is missing")

let sendEmail (email:string) =
  printfn "sending email to %s..." email

let handleError (error:Error) =
  match error with
  | InvalidEmail email -> printfn "bad email: %s" email
  | DatabaseError ex   -> printfn "db error: %A" ex

"hello@world"
|> validateEmail
|> Trial.either sendEmail handleError

Expected behavior

Code should compile.
If the email is valid, then sendEmail should be called, else handleError

Actual behavior

Compiler error 1:

Type mismatch. Expecting a
    'string * Error list -> 'a'    
but given a
    'string -> unit'    
The type 'string * Error list' does not match the type 'string'F# Compiler(1)

Compiler error 2:

Type mismatch. Expecting a
    'Error list -> 'a'    
but given a
    'Error -> unit'    
The type 'Error list' does not match the type 'Error'

Known workarounds

If I change the signature of the two functions, it works.

let sendEmail (email:string, errors: Error list) =
  printfn "sending email to %s..." email

let handleError (errors:Error list) =
  for error in errors do
  match error with
  | InvalidEmail email -> printfn "bad email: %s" email
  | DatabaseError ex   -> printfn "db error: %A" ex

But this seems like an unneccessary workaround for me.

1.) Why would I want a (always empty) error list in the success handler?

2.) How could there be more than one error in the failure handler?
I was expecting that the Result always contains the first error.

My expectations are based on this article: https://fsharpforfunandprofit.com/posts/recipe-part2/

Using extensions from VB.net

Forked the repository here: https://github.com/kellerd/Chessie

Tried to get Extensions working in .NET.

Added a test project for it:
https://github.com/kellerd/Chessie/tests/Chessie.VisualBasic.Test/Chessie.VisualBasic.Test.vbproj

The easiest fix I found was to add [<assembly: ExtensionAttribute()>] to Assembly.fs and include it into the fs project.

Ran into an issue when using FAKE, where it won't let me add an attribute in your genFSAssemblyInfo section without specifying parameters to the attribute.

I added an issue to FAKE in the mean time, maybe it'll get some traction, to add the feature
fsprojects/FAKE#1115, before I try to create a PR myself

Original problem:
https://github.com/kellerd/Chessie/tree/master

Potential fix:
https://github.com/kellerd/Chessie/tree/Intermediatefix

Unless someone has come across this before or has more experience with it.

Async Adapter functions

I was wanting some adapter functions that lived in the AsyncResult space. I shoehorned these into one of the projects I'm currently working on.

        // ('a -> Result<'b,'c>) -> ('a -> AsyncResult<'b,'c>)
        let resultToAsync (f : 'a -> Result<'b,'c>) x =  x |> f |> Async.singleton |> AR 
        // ('a -> 'b) -> (AsyncResult<'a,'c> -> AsyncResult<'b,'c>)
        let liftAsyncResult (oneTrackFunction : 'a -> 'b) (twoTrackInput : AsyncResult<'a,'c>) = asyncTrial {
                let! twoTrackResult = twoTrackInput
                return oneTrackFunction twoTrackResult
            }
        // ('a -> AsyncResult<'b,'c>) -> (AsyncResult<'a,'c> -> AsyncResult<'b,'c>)
        let bindAsyncResult (switchFunction : 'a -> AsyncResult<'b,'c>) (twoTrackInput : AsyncResult<'a,'c>)= asyncTrial {
                let! twoTrackResult = twoTrackInput
                return! switchFunction twoTrackResult
            }       

The use case I had in mind was:

        let updateSomeRecord = resultToAsync validate
                                >> bindAsyncResult queryDatabase
                                >> liftAsyncResult saveResults 
                                >> Async.ofAsyncResult

Probably not the best implementation and names need to change. Should I make a PR for this?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.