@wallymathieu I wonder if you're using the library for some projects, prototyping or just playing with the exotic typeclassy features?
I'm just curious and at the same time I would like to know if there's any stuff you would like to see added to this lib.
I'm looking into extension libraries of f# in order to write some nice f#. I've started using dotnet core quite a lot, so it natural to try to transition libraries so that you can use them from that environment.
I like for instance common computation expressions, since they can make for cleaner code.
I don't have a specific use case in mind right now.
One thing that might need transitioning is add Result<,> instead of Choice<,>. There are a lot of libraries still using Choice<,> out there, so probably something that will take years to transition.
I like for instance common computation expressions, since they can make for cleaner code.
Precisely right now I'm trying to improve them (see https://github.com/gusty/FSharpPlus/issues/32)
One thing that might need transitioning is add Result<,>
Yes, and also the ValueTuple, I still didn't find the time to analyze the impact, but would be nice to transition, or even better to include them keeping the existing ones. Feel free to open an Issue regarding this.
Thanks, for your feedback, and also your contributions, this project is too big for a single developer, that's why I'm asking, because I dream to make it a community effort. One problem is that the typeclassy stuff is very complicated to get people contributing, but that's just a part of the project, there are many areas to contribute, specially in the design discussions.
I would love to grok the typeclassy things. A lot of the monads have been done in extcore. Maybe inspiration can be found there.
I think ExtCore takes a different approach. As most other base libraries it defines the classic monads and some combinations of them, by hand. Here we have monad transformers which allow us to combine them at discretion. Both approaches have goods and bads, I'm not a big fan of Monad Transformers, even in Haskell, but at the moment it's the most flexible approach.
I think most basic monads from ExtCore are already implemented here, let me know if we're missing something.
Regarding the computation expressions, I did had a look at the way there were implemented there in ExtCore, and found some inspiration, but also found they have to choose one specific implementation (sequencing fx or monad plus) while leaving away the other one.
Having said all this, I don't discard adding some common custom combined monads at some point, as the ones in ExtCore or in FSharpX, or as the AsyncSeq.
Btw, one thing I've been curious about is the inherit Default1. Is it in order to be able to declare several methods with different statically resolved type parameters?
It's a way to have some control over the overload resolution, specially for the default implementations, therefore the name.
The basic idea is that we have default implementations, for example the method Join for a specific type can be derived automatically if that type is a monad that has Bind and Return (see monad) but you can also have a specific Join overload for that type which might be more optimized.
So if the overload for that type doesn't exists it has to use the default implementation, which is generic for any monad. In that case we want the overload resolution to give priority to the specific type and if it doesn't exists, default to the default implementations.
Since overload resolution rules give priority to base classes by having a default that is a superclass of the class containing the overloads we achieve such behavior.
Aaa, interesting! Thanks for the explanation!
I find this library really interesting. It takes the f# language in a different way than perhaps intended by dsyme, so perhaps having a fork of component-design-guidelines would be appropriate for f#+ style code?
I'm not getting the feeling that you intend for f#+ code to be consumed by for instance c#? So many of the guidelines related to interop don't really apply.
Yes, a guideline and in general more doc is definitely something we should aim to, if we expect more adoption.
By taking advantage of your fresh point of view as adopter of this library (mine is well contaminated), do you have any idea of what stuff such a guideline should cover?
Regarding C# I changed my mind many times :)
It's really a nice to have, but there are many problems, some of them don't exists anymore with current state of things, but the main issue is that inlined stuff doesn't work from C#.
So, I decided to focus initially in F# and then see if there is space for some C# usability.
See for example the issue regarding extension members to get a feeling of it. Of course feel free to reopen the discussion.
To add more context, I imagine guidelines and C# integration in different scenarios:
The source for the validation library is more intended as a place to work on it without polluting f#+. Perhaps some of the tests could be useful and a curated amount of methods if it's something that should be part of f#+. If it's supposed to be a separate lib, then perhaps it should be named something else like FSharpPlus.Validations ?
Yes, actually I took it as an example.
Then at some point of course we can decide to merge it here, which if you ask me I think would be a really good addition, not to say a must have, given the amount of blogs you see about validation and ROP nowadays.
BTW, also the FsCheck stuff you're doing there is something that definitely belongs to this library, given all the rules we're trying to stick to. We never checked. I was more worried about testing compile-time behavior than run-time.
Some of the ROP and validations could perhaps benefit from seeing a f#+ implementation with a bit more thought.
Since I've started reading more about it, it feels like there are some confusing aspects of mixing validations with result since one should be applicative and one should not.
Some of the ROP and validations could perhaps benefit from seeing a f#+ implementation with a bit more thought.
Sure, but that requires not just writing the code. It would require writing examples and possible blogging about it.
Applicative validation was something I had in mind to add since many years, along with other stuff like LazyList (with its transformer), RoseTree, Observable extensions, Tasks, Quotations, Lenses and many other areas that I think are key to a decent base library.
If all the above stuff is not here today is just because I don't have infinite time and was more focused on the type-classy stuff that gives me many headaches, including digging into the F# compiler code and eventually trying to fix it. But that's just only one aspect of this library (although it's probably the most distinctive).
one is applicative and one is not.
Which one is not applicative?
Result
It is:
[<Extension>]static member Map (x : Result<_,'E> , f : 'T->'U, [<Optional>]_mthd : Map) = Result.map f x
static member ``<*>`` (f:Result<_,'E>, x:Result<'T,'E> , [<Optional>]_output:Result<'b,'E>, [<Optional>]_impl:Apply) = Result.apply f x: Result<'U,'E>
Maybe you mean Alternative?
You are right of course. 馃憤
In that case, I would say none of them is in the strict sense an Alternative, simply because there is no unique empty value.
But, both of them can be considered as Alt which only requires <|>.
Choice has many ways to define <|> we'll probably end up implementing it as the mOrElse function, but there are other valid implementations.
For Validation the situation seems to be less confusing, probably because it's more specific, but the behaviour is exactly the same.
Although Result is isomorphic to Choice it express (by the names) the intention, so here it's also clear the mOrElse definition.
BTW, I'm always tempted to add an (possible ad-hoc) IsFailure method to get a generic isFailure function.
This is interesting to generalize over types that model failures (all the above, plus option) and it is particularly interesting to allow traversing infinite lists.
Why the sense to include Alt in f#+.
What do you mean? Are you asking to include Alt?
Alt as most other typeclasses is already implicitly included.
We just need to add it to the docs.
We don't handle typeclasses like in Haskell here, we just generalize over the individual operations.
Then we name some 'abstractions' according to rules and operations.
If that's not what you mean please let me know.
As you said, even if the abstraction are not possible to have part of the language, they can still be in the docs.
Yes, well is not that is not possible, I think there is an (ugly) way to enforce group of operations.
But the question is whether it makes sense.
Nowadays in Haskell as you may have already seen, they have a lot of repetitive and redundant code, because they also have more granular type classes, and everyday they are trying to come with more partitions.
In the end typeclasses also have to obey (run-time) rules, so by doing that effort you still don't have any compiler guarantee. So why go in their direction when they're are going to ours?
Feel free to add Alt to the docs, or to name the type parameters as 'Alt where it makes sense.
PS: I think there is an old issue when we started FsControl, where we discussed all this mess in the Haskell world and finally we decided to take this direction.
I've seen some of the mess that is Haskell. I think I noticed that there are a lot of weirdness when it comes to record syntax. I think I could partially implement type classes. Sometimes it feel more like a thing to enable overloading. But there are lots of interesting things that you can learn from Haskell (I've not learned enough though).
Sometimes it feel more like a thing to enable overloading.
Yes, that was the original goal. Typeclasses is the way to do overlaoding in Haskell
But there are lots of interesting things that you can learn from Haskell (I've not learned enough though).
Millions, but since it has two decades (as of today ;) ) there are lot of lesson learned stuff as well. I'm sure that if they start doing Haskell again (form scratch) there will be many differences.
Have I got it right?
Operation | F#+ | F# | Haskell
-- | -- | -- | --
map | | 聽 | <$>
apply (combine) | <> | 聽 | <>
alternatives: unit element | empty | 聽 | empty
alternatives: binary operation | <\|> | | <\|>
monoids: unit element | zero | 聽 | 聽mempty
monoids: binary operation | ++ | | mappend
List.append | 聽 | @ | ++
聽 | 聽 | << | .
聽 | 聽 | <\| | $
聽 | 聽 | = | ==
聽 | 聽 | <> | =/
Yes, looks good.
Maybe it's possible to collapse F#+ and F# in one.
The idea is that there shouldn't be differences unless you open a specific namespace like the Math operators which redefines some F# core stuff.
That table should go to the docs !
I've merged the columns:
Operation | F#+ / F# | Haskell
-- | -- | --
map | | <$>
apply (combine) | <> | <>
alternatives: binary operation | <\|> | <\|>
append | ++ | 聽
List.append | @ | ++
聽 | << | .
聽 | <\| | $
聽 | = | ==
聽 | <> | =/
Most helpful comment
I've merged the columns:
Operation | F#+ / F# | Haskell
-- | -- | --
map | | <$>
apply (combine) | <> | <>
alternatives: binary operation | <\|> | <\|>
append | ++ | 聽
List.append | @ | ++
聽 | << | .
聽 | <\| | $
聽 | = | ==
聽 | <> | =/