Skip to content

Conversation

@3Rafal
Copy link
Contributor

@3Rafal 3Rafal commented Oct 10, 2020

Added safe zip function zipShortest.
It's behavior is equivalent to Haskell zip which I think is quite reasonable.
Naming is already used in .NET ecosystem in MoreLinq C# library [Source]

@adz
Copy link
Contributor

adz commented Oct 10, 2020

I like your idea!

I thought this was how List.zip in core worked already, but I was wrong. It throws exception if different sized lists are zipped.

Unfortunately, F#+ seems a little inconsistent:

  • extensions for Enumerator, Dictionary, IReadOnlyDictionary, Map implement zip just like your zipShortest (i.e. it stops when one enumerator stops, and skips over missing keys for map, etc).
  • NonEmptyList.fs and NonEmptySeq.fs in FSharpPlus/Data directly call List.zip / Seq.zip, so these throw.

So for completeness, we should probably implement zipShortest for NonEmptyList, NonEmptySeq.

I'm not sure if it's worth also implementing zipShortest as zip in the other cases?

@adz adz requested a review from gusty October 10, 2020 12:53
@adz
Copy link
Contributor

adz commented Oct 10, 2020

Oh now I notice the other pr!

Well seems to me still makes sense to implement for non empty list... tryZip could be a separate thing.

@3Rafal
Copy link
Contributor Author

3Rafal commented Oct 10, 2020

@adz , you're right. I've added implementation for nelist and neseq as you suggested.
When it comes to tryZip, I'm not convinced it is a good idea, so I won't implement it now.

@gusty
Copy link
Member

gusty commented Oct 10, 2020

Unfortunately, F#+ seems a little inconsistent:

Again it worth clarifying is not our goal to fix FSharp.Core
If they took the unfortunate decision to make lists and arrays to fail when zipping we have to honor it, if we have a nelist it can't behave differently to the normal list, but same goes for neseq.

So these inconsistencies comes from F# core and we can't fix them. We should instead create different function which behave in a consistent way, take for instance the example of take and skip, they fail but we introduced other functions drop and limit that don't.

@gusty
Copy link
Member

gusty commented Oct 10, 2020

We could however, define our generic zip as zipShortest, that would solve inconsistencies at the generic level.
Same would apply for map2.

But I definitely like the zipShortest in the extensions.

@3Rafal
Copy link
Contributor Author

3Rafal commented Oct 10, 2020

@gusty , I've introduced changes according to your remarks. now generic zip is using safe functions only.

@3Rafal 3Rafal changed the title Add zipShortest function Add zipShortest function and make generic Zip safe Oct 10, 2020
let zipShortest (a1: ResizeArray<'T1>) (a2: ResizeArray<'T2>) =
let len = min a1.Count a2.Count
[| for i in 0..(len-1) -> a1.[i], a2.[i] |]
|> ResizeArray
Copy link
Member

Choose a reason for hiding this comment

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

I will accept it as it is, but not sure if this is the most efficient implementation in terms of allocations.

Copy link
Contributor Author

@3Rafal 3Rafal Oct 10, 2020

Choose a reason for hiding this comment

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

Changed it to efficient version both here and in ResizeArray.
I've checked it with #time and implementations suggested by you are considerably faster. (even 2-3x on my machine)

@3Rafal 3Rafal requested a review from gusty October 11, 2020 14:07
@gusty gusty merged commit 4c61126 into fsprojects:master Oct 11, 2020
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