Skip to content

Conversation

@fxdmhtt
Copy link
Contributor

@fxdmhtt fxdmhtt commented Jun 5, 2025

The signature of GroupBy.Invoke function is abnormal, which causes the secondary encapsulated 'Collection<'T> type to be incorrectly identified (identified as Id<'T>).

Refer to ChunkBy.Invoke, this should be just a typo.

static member GroupBy (x: 'T [] , f: 'T->'Key, _: ('Key*('T [])) [] , [<Optional>]_impl: GroupBy) = Seq.groupBy f x |> Seq.map (fun (x, y) -> x, Seq.toArray y) |> Seq.toArray

static member inline Invoke (projection: 'T->'Key) (source: '``C<'T>``) : '``C<'Key * 'C<'T>>`` =
static member inline Invoke (projection: 'T->'Key) (source: '``Collection<'T>``) : '``Collection<'Key * 'Collection<'T>>`` =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note the ticks in the type signature. The C here is more for documentation rather than an actual type

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it won't change any behavior. Not even a public signature.
But it reads better, so we can accept the PR as a code readability improvement.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For sure, I’m wondering if @fxdmhtt has some issue with code? Something that does not compile?

@gusty
Copy link
Member

gusty commented Jun 5, 2025

The signature of GroupBy.Invoke function is abnormal, which causes the secondary encapsulated 'Collection<'T> type to be incorrectly identified (identified as Id<'T>).

@fxdmhtt please create an issue for this. with a small repro, then we can help and reference eventually a PR that will address it.

We'll accept this PR but it's unlikely that it will solve any issue.

@gusty gusty changed the title Update Collection.fs Improve internal type signature Jun 5, 2025
@fxdmhtt
Copy link
Contributor Author

fxdmhtt commented Jun 5, 2025

I have seen your reply and I completely agree with what you said.

I think it is more of my own problem and I didn't want to bother you about it.

Please allow me to extract a minimal reproducible code tomorrow. Thank you very much!

@fxdmhtt
Copy link
Contributor Author

fxdmhtt commented Jun 6, 2025

Thank you very much.

The minimal example code is as follows:

open FSharpPlus

let inline groupby (key: 'T -> 'Key when 'Key : equality) (sequence: '``Collection<'T>``) : Map<'Key, '``Collection<'T>``> =
    sequence
    |> groupBy key
    |> Map.ofSeq

I will get a wavy line error on groupBy:

The type 'Internals.Id<'Key * Internals.Id<'T>>' is not compatible with the type '('Key * 'Collection<'T>) seq'.

This code doesn't really mean anything, I'm just more familiar with Python so I'm trying to simulate the behavior of the Toolz package. This is a toy.

Specifically, I'm trying to wrap the generic groupBy as Toolz.groupby

I'm a beginner in F# and don't know if this problem is caused by FSharpPlus, but as of now, I really don't have any idea to solve this compilation error.

FSharpPlus: 1.7.0
OS: Windows 10
.NET: 9.0

Thanks again!

Additional information:

I found that when the function signature is changed to the following:

let inline groupby (key: 'T -> 'Key when 'Key : equality) (sequence: '``Collection<'T>``) =
    sequence
    |> groupBy key
    |> Map.ofSeq

that is, the signature of the function output is removed.

the compilation error will disappear, but the type inference will not be able to recognize the real information.

The Ionide plugin infers:

val inline groupby:
   key     : ('T -> 'Key) ->
   sequence: 'Collection<'T> (requires static member GroupBy )
          -> Map<'b,'c> (requires comparison)

I don't know how to modify

@gusty
Copy link
Member

gusty commented Jun 9, 2025

This looks like a bug/limitation.

I mean, your repro code goes a bit far into the limits of this library / F# type inference limitations.

Having said that, at first sight it looks easy to solve. I can give it a try.

@gusty
Copy link
Member

gusty commented Jun 10, 2025

@fxdmhtt I managed to fix your issue here #633

For this PR, could you also change the other signatures in this files the same way?
I think there is another C<'T> somewhere.

@fxdmhtt
Copy link
Contributor Author

fxdmhtt commented Jun 11, 2025

There are many C<'T> in the code, but the only lonely C<'T> is in the GroupBy function. I don't know which "another" you are referring to.

Have you considered replacing all C<'T> in batches?

Copy link
Member

@gusty gusty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See in Distinct, DistinctBy, Rev, and all Sort related Invokables have also the abbreviated C<T>` type signature.

Please apply the same change to them, so we can merge this.

@gusty
Copy link
Member

gusty commented Jun 11, 2025

There are many C<'T> in the code, but the only lonely C<'T> is in the GroupBy function. I don't know which "another" you are referring to.

See my review, or just do a find C<'T>.

Have you considered replacing all C<'T> in batches?

I rarely do these kind of PRs that only impact code readability, I'm not saying it's bad, it's just that since I have limited time I prefer to focus myself in solving functionality issues. So, it's good to have collaborators who take care of code uniformity. It definitely helps in the long run.

…ve clarity and consistency in type references for collection operations. Enhances readability and aligns with naming conventions.
@fxdmhtt
Copy link
Contributor Author

fxdmhtt commented Jun 11, 2025

There are many C<'T> in the code, but the only lonely C<'T> is in the GroupBy function. I don't know which "another" you are referring to.

See my review, or just do a find C<'T>.

Have you considered replacing all C<'T> in batches?

I rarely do these kind of PRs that only impact code readability, I'm not saying it's bad, it's just that since I have limited time I prefer to focus myself in solving functionality issues. So, it's good to have collaborators who take care of code uniformity. It definitely helps in the long run.

Please review the patch

Copy link
Member

@gusty gusty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK from my side, let's see if CI agree as well ;)

@fxdmhtt
Copy link
Contributor Author

fxdmhtt commented Jun 11, 2025

Sorry. I saw the CI error, but I don't have the ability to fix it.

In fact, I raised this issue because I encountered difficulties in using F# type inference.

I need your help.

Thank you very much.

@gusty
Copy link
Member

gusty commented Jun 11, 2025

No worries. I will fix it and merge it.
Thanks !

@gusty
Copy link
Member

gusty commented Jun 12, 2025

Fixed

For the record: the change you did in Collections is OK, and that was the idea, change it in Invoke's static members.

Now, in some places, for instance in all the occurrences in Indexable, things were different, they were already being used in Invoke's and intentionally different in some overloads, to avoid type inference propagation of constraints. So there's nothing to change there, I mean you could eventually change them collection<'t> (all with lowercase) and that's what I did.

@gusty gusty merged commit 007b8cc into fsprojects:master Jun 12, 2025
4 checks passed
@fxdmhtt
Copy link
Contributor Author

fxdmhtt commented Jun 13, 2025

Thank you for your work.

Can I ask a question:

A string wrapped in double backticks, no matter what is inside, is generally regarded as a literal string, even in type inference?

What I mean is, whether it is 'Collection<'T> or ^Collection<'T> (although I am not sure what the difference is in inline function), Collection<'T> is a literal string, and the 'T in it has no special meaning, it is just part of the literal string. The use of 'T elsewhere in the same function signature is a new type that is completely unrelated to 'Collection<'T> (no inclusion relationship).

Is this the correct understanding?

@fxdmhtt fxdmhtt deleted the patch-1 branch June 13, 2025 01:22
@gusty
Copy link
Member

gusty commented Jun 13, 2025

Yes, whatever is inside the backticks is not being parsed, so no matter what you write there, it won't have any different effect.
Of course, unless it matches or differ from existing ones, which was the case here.

@wallymathieu
Copy link
Member

@fxdmhtt thanks for the contribution! 👍

wallymathieu pushed a commit that referenced this pull request Jun 14, 2025
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.

3 participants