Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typeclasses #24

Closed
wants to merge 32 commits into from
Closed

Typeclasses #24

wants to merge 32 commits into from

Conversation

gusty
Copy link
Member

@gusty gusty commented Dec 22, 2011

Existing code was refactored in order to define Typeclasses in a more generic way.

+ Type annotations to guide type inference to the right signature.
@panesofglass
Copy link
Contributor

This looks good to me.

@mausch
Copy link
Member

mausch commented Jan 2, 2012

@forki
Copy link
Member

forki commented Jan 4, 2012

what's the status on this?

@mausch
Copy link
Member

mausch commented Jan 4, 2012

@forki see discussion above. This needs more use to uncover all problems so we can make an informed decision about making this part of master.

@ghost
Copy link

ghost commented Mar 8, 2012

Have there been any news on this subject?

@mausch
Copy link
Member

mausch commented Mar 8, 2012

@ohwow status is still the same. Any input would be appreciated (in the mailing list).

@mausch
Copy link
Member

mausch commented May 8, 2012

Just as an update: I have been working a little on this in my fork: https://github.com/mausch/fsharpx/tree/typeclasses, and found a number of cases where type inference breaks or seemingly correct code won't typecheck.
As usual, help is always welcome.
Also, I talked to Gustavo a while ago, he mentioned he was working on an alternative that had better type inference, so watch http://code.google.com/p/fsharp-typeclasses/ .

@gusty
Copy link
Member Author

gusty commented Jun 13, 2012

Hi

As Mauricio said, I'm working in an alternative solution.

http://code.google.com/p/fsharp-typeclasses/#Alternative_Solution
I just uploaded this alternative version of the approach, without
operators, which will make it more flexible as we can specify explicitely
the constraint when calling the static method.

It requires to fix a bug in the F# Parser, but it's included, so you can
recompile F# and experiment with it (that's what I will be doing from now
on).

Regards

Gustavo

On 8 May 2012 17:37, Mauricio Scheffer <
reply@reply.github.com

wrote:

Just as an update: I have been working a little on this in my fork:
https://github.com/mausch/fsharpx/tree/typeclasses, and found a number of
cases where type inference breaks or seemingly correct code won't typecheck.
As usual, help is always welcome.
Also, I talked to Gustavo a while ago, he mentioned he was working on an
alternative that had better type inference, so watch
http://code.google.com/p/fsharp-typeclasses/ .


Reply to this email directly or view it on GitHub:
#24 (comment)

@mausch
Copy link
Member

mausch commented Jul 22, 2012

@ffogd helped out with a couple of issues: mausch@eda97d6#commitcomment-1613711 mausch@4d2f760#commitcomment-1613633

@gusty
Copy link
Member Author

gusty commented Aug 30, 2012

Q: Why did you choose Choice1of2 as the "Right Choice"? Is there any special reason?
The problem I see is we have here the Right parameter at the Left side, ie: Choice<'right,'wrong>.
In any case we can't partially apply the type to express it as a Monad (Functor or Applicative) because at the moment we don't have higher order kinds in F#, but still breaks the convention and the mnemonic ("right" also means "correct") and I think it can be tricky for a person coming from Haskell or other languages like Scala.
Even if it is not used as a "Value or Error" the idea is to fix the first parameter and play with the second.

@mausch
Copy link
Member

mausch commented Aug 30, 2012

Async.Catch uses that convention, so we went with that.
Personally, my mnemonic is "first assume things go well", therefore Choice1Of2 carries the "Right" value.
You can still partially apply the type arguments at the datatype level, e.g.

data AEither a b = ARight a | ALeft b
data AMaybe a = AEither a ()

For instances, I think you can use a Flip type combinator, though I'm not sure and it would still be kinda annoying.

@gusty
Copy link
Member Author

gusty commented Aug 30, 2012

OK, I guess that's a good reason. My next question is about Nullable.
Since we can't create an Applicative Functor for Nullable it makes no sense to define a Nullable Monad.
Having Nullable as a monad would lead to compilation errors when using generic functions, not just ap.
As Functor is probably fine, as long as you don't try to map to a reference type, ie fmap string (Nullable 5)

@mausch
Copy link
Member

mausch commented Aug 30, 2012

Good point, I didn't realize that Nullable isn't really a monad. I don't think it's even a functor.
Still, Nullable.bind, Nullable.map, Nullable.lift2 etc seem useful, maybe we could just rename them or otherwise make it very explicit in the comments that they're not functorial, monadic, etc.

@gusty
Copy link
Member Author

gusty commented Aug 30, 2012

I think is a Restricted Monad, like Ord a => Set a (F# notation: Set<'a>
when 'a : comparison).
There you have the same problem, since a function is not an instance of Ord
there is no Applicative instance.
But AFAIK they obey all Functor laws, if you consider the Category
restricted to those restricted types.

In Haskell it's a problem to code Restricted Monads, you need an extension,
but in F# using this technique is fine as long as you know what you're
doing.

For now,as you said, we can just add a comment making it very explicit that
it's a Restricted Monad.

Gustavo

On 30 August 2012 20:19, Mauricio Scheffer notifications@github.com wrote:

Good point, I didn't realize that Nullable isn't really a monad. I don't
think it's even a functor.
Still, Nullable.bind, Nullable.map, Nullable.lift2 etc seem useful, maybe
we could just rename them or otherwise make it very explicit in the
comments that they're not functorial, monadic, etc.


Reply to this email directly or view it on GitHubhttps://github.com//pull/24#issuecomment-8169109.

@panesofglass
Copy link
Contributor

What's the status on this?

@gusty
Copy link
Member Author

gusty commented Feb 26, 2013

Since I did this pull request, this approach was refined and finally I decided to create a new Project: FsControl.

The goal is to get the same functionality but in a less intrusive way, I mean not forcing everybody to a specific name convention or style (Haskell vs F#).

At the same time there were some discussions about splitting FSharpx in separated DLLs.
Also there were people complaining about methods published in FSharpx , wanting to move them to a specific module.
This new project is aligned with those discussions.

It contains just the basic overloads but does not define generic functions, so if used in FSharpx or other project it's the project which should create the generic functions.
It also allows the project to add overloads for his types, so even if you don't want to use or define generic functions in your project you can add overloads to your types, someone else might be interested to use your types in generic functions.

FsControl is basically an overload repository, there might be projects that add overloads to it, projects that use the overloads for generic functions and projects that do both.
Mauricio did an example which shows how to use FsControl.

For F#x I propose to link this dll, add overloads for all Monads, Applicatives, etc and eventually define some generic functions inside a module for people wanting to use this approach.
I can do a branch to show how it will look like.

UPDATE

FsControl is dead, now we have F#+ and we don't need to link anything, as long as we add static members with the required signature both projects will integrate nicely.

@jackfoxy
Copy link
Contributor

Whether in FSharpx or the new FsControl project, please write XML comments (documentation) on all types and functions, and write a comprehensive readme.md. Otherwise this excellent work is only accessible to the most motivated individuals. The way to spread adoption of F# is to make work like this more accessible.

@mausch
Copy link
Member

mausch commented Feb 26, 2013

Also worth noting is that this has to be within FSharpx, i.e. if we want fmap for RoseTree, the Functor instance has to be defined either along with the definition of the Functor "typeclass" or when defining the RoseTree type.
Otherwise you run into the same problem as with orphan instances in Haskell.
So either FSharpx takes a dependency on FsControl, or it includes/merges FsControl, but the instances for the typeclasses can't be defined in a third assembly.
Technically speaking, another possibility would be having FsControl depend on FSharpx, but that doesn't seem like a good idea, it would be like having the Functor class depend on particular instances of it.
Gustavo, please correct me if I'm wrong :)

As the Haskell wiki says in http://www.haskell.org/haskellwiki/Orphan_instance : "If you encounter a missing instance for a class or a type of a package, resist to define your own orphan instance, because it will likely collide with such instances of other packages, or it will collide with new instances added in later versions of that package. Instead ask the package author to add your instance."

I'd just take the dependency on FsControl. Since FsControl doesn't export any operators or even functions, we can later decide whether we want to add a new module with the overloaded functions/operators binding to typeclasses or not, but that would be a separate discussion.

Also, this wouldn't have any impact on current client code of FSharpx. Users would be able to choose between the typeclassy way of doing things, or the traditional, more fsharpish style. Both have pros and cons.

@ghost
Copy link

ghost commented Jun 24, 2013

Can we close/archive this request? It is very old.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants