Sets, Functors and Eq confusion

前端 未结 3 1715
南旧
南旧 2020-12-07 16:35

A discussion came up at work recently about Sets, which in Scala support the zip method and how this can lead to bugs, e.g.

scala> val words          


        
相关标签:
3条回答
  • 2020-12-07 16:55

    Well, Set can be treated as a covariant functor, and as a contravariant functor; usually it's a covariant functor. And for it to behave regarding equality one has to make sure that whatever the implementation, it does.

    Regarding Set.zip - it is nonsense. As well as Set.head (you have it in Scala). It should not exist.

    0 讨论(0)
  • 2020-12-07 16:59

    Another argument against Set being a Functor - it is widely accepted that being a Functor allows you to transform the "elements" of a "collection" while preserving the shape. [...] Clearly, any functor instance for Set has the possibility to change the shape, by reducing the number of elements in the set.

    I'm afraid that this is a case of taking the "shape" analogy as a defining condition when it is not. Mathematically speaking, there is such a thing as the power set functor. From Wikipedia:

    Power sets: The power set functor P : Set → Set maps each set to its power set and each function f : X → Y to the map which sends U ⊆ X to its image f(U) ⊆ Y.

    The function P(f) (fmap f in the power set functor) does not preserve the size of its argument set, yet this is nonetheless a functor.

    If you want an ill-considered intuitive analogy, we could say this: in a structure like a list, each element "cares" about its relationship to the other elements, and would be "offended" if a false functor were to break that relationship. But a set is the limiting case: a structure whose elements are indifferent to each other, so there is very little you can do to "offend" them; the only thing is if a false functor were to map a set that contains that element to a result that doesn't include its "voice."

    (Ok, I'll shut up now...)


    EDIT: I truncated the following bits when I quoted you at the top of my answer:

    For example, this quote on the Haskell wiki (note that Traversable is a generalization of Functor)

    "Where Foldable gives you the ability to go through the structure processing the elements but throwing away the shape, Traversable allows you to do that whilst preserving the shape and, e.g., putting new values in."

    "Traversable is about preserving the structure exactly as-is."

    Here's I'd remark that Traversable is a kind of specialized Functor, not a "generalization" of it. One of the key facts about any Traversable (or, actually, about Foldable, which Traversable extends) is that it requires that the elements of any structure have a linear order—you can turn any Traversable into a list of its elements (with Foldable.toList).

    Another, less obvious fact about Traversable is that the following functions exist (adapted from Gibbons & Oliveira, "The Essence of the Iterator Pattern"):

    -- | A "shape" is a Traversable structure with "no content," 
    -- i.e., () at all locations.
    type Shape t = t ()
    
    -- | "Contents" without a shape are lists of elements.
    type Contents a = [a]
    
    shape :: Traversable t => t a -> Shape t
    shape = fmap (const ())
    
    contents :: Traversable t => t a -> Contents a
    contents = Foldable.toList
    
    -- | This function reconstructs any Traversable from its Shape and
    -- Contents.  Law:
    --
    -- > reassemble (shape xs) (contents xs) == Just xs
    --
    -- See Gibbons & Oliveira for implementation.  Or do it as an exercise.
    -- Hint: use the State monad...
    --
    reassemble :: Traversable t => Shape t -> Contents a -> Maybe (t a)
    

    A Traversable instance for sets would violate the proposed law, because all non-empty sets would have the same Shape—the set whose Contents is [()]. From this it should be easy to prove that whenever you try to reassemble a set you would only ever get the empty set or a singleton back.

    Lesson? Traversable "preserves shape" in a very specific, stronger sense than Functor does.

    0 讨论(0)
  • 2020-12-07 17:16

    Set is "just" a functor (not a Functor) from the subcategory of Hask where Eq is "nice" (i.e. the subcategory where congruence, substitution, holds). If constraint kinds were around from way back then perhaps set would be a Functor of some kind.

    0 讨论(0)
提交回复
热议问题