3.5 Naming Conventions
Some names are inconsistent. For example Functor is not called Mappable while Traversable is not named after abstract nonsense. It is best to focus on what things are instead of what they are called.
3.5 Naming Conventions
Some names are inconsistent. For example Functor is not called Mappable while Traversable is not named after abstract nonsense. It is best to focus on what things are instead of what they are called.
I wanted to rename "Monoid" to "Joinable" in my code ("Concatenatable" is too long). But it turns out you can't alias a type class while maintaining compatibility with libraries that use it.
Do tell me more about how "concatenatable" is a "completely wrong" impression of what Monoids are for. I know you can use them to, like, multiply using abstract nonsense, but that's not why you care what a Monoid is. Monoids let you generalize `mappend` over many kinds of sequences.
People can cope with all kinds of bad things, regardless of whether or not they know haskell. That is not an argument in favor of bad things.
>I know you can use them to, like, multiply using abstract nonsense
What? There's nothing "abstract nonsense" about it. Integers are monoids. Things that can be appended is a subset of monoids, not a description of them.
It's such a Haskelly response to say that I am not allowed to use a concept for what it was designed for, unless I use it in its full generality.
No, it is partially wrong, as I said. Appending describes a subset of monoids, not monoids.
>It's such a Haskelly response to say that I am not allowed to use a concept for what it was designed for
What on earth are you talking about? I am not a haskell person and I said nothing even remotely resembling that.
I think that one bad habit that Haskell promotes is statements of this form, which are true in Haskell because of the way Haskell forces you to define typeclasses, but aren't really "true" of the concepts modeled by typeclasses. (Integer, +, 0) defines a monoid, as does (Integer, ×, 1).
> Things that can be appended is a subset of monoids, not a description of them.
The key operation that defines a monoid is the append operation ("mappend" in the definition of the Haskell typeclass Monoid, to avoid collision with the list-specific "append" operation), which for the monoid of integers over addition is (as the name suggests) addition.
>The key operation that defines a monoid is the append operation
No, it is the sole monoid operation. It is named mappend in haskell, but that does not make everything it encompasses into appending. Ask someone what operations can be done on "appendables" and you will get lots of answers like looping, sizeof, etc. Append always refers to collections in other languages, so the argument that it would help people to call something different "appendable" for those people is silly.
No, the specific statement is true neither in reality nor in Haskell, though statements of that form (which is what I said) are often true in Haskell (e.g., List is a Monad) though not reality.
Integers are not monoids. As I stated in GP, the combination (Integer, +, 0) defines a monoid -- as does (Integer, ×, 1); there's other monoids one could define on Integers, though those are the two most obvious and useful ones. Haskell, because its designed to make statements of the form type is a typeclass has to do one of two things to support the case where multiple useful instances of a typeclass can be defined involving a particular type -- one is the newtype wrapper approach used for Sum and Product with numeric types as monoids, with the base type participating in none of the instances; the other is to choose a primary instance that the base type participates in, and relegate the others to the newtype treatment (this is what is done with lists as monads in Haskell).
Both of these approaches are workarounds for the problem that typeclass instances aren't naturally defined by a participating type alone, but by the combination of a participating type, and one or more other values (some of which are usually functions.)
This is simply being pedantic. We're all well aware of the meaning of what I said, as it is how it is almost always said.
>Both of these approaches are workarounds for the problem that typeclass instances
That's not a problem, it is the point. That is what typeclasses were intended to be.
{-# LANGUAGE ConstraintKinds #-}
import Data.Monoid
type Joinable = Monoid
something :: Joinable m => m -> m -> m
something = (<>)
But like MustardTiger says, don't. newtype Sum a = Sum { getSum :: a }
instance (Num a) => Monoid (Sum a) where
mempty = Sum 0
mappend (Sum a) (Sum b) = Sum (a + b)
Finally, and perhaps most importantly, I seriously doubt anybody reading your codebase is going to do so in complete isolation of the rest of the Haskell ecosystem. They are going to encounter the word "monoid", so you're not really doing them any favors by hiding it from them. You're just forcing them to jump through the mental hurdles of reconciling your wording with what's used everywhere else. type Natural = [()]
zero, one, two, three, four :: Natural
zero = []
one = [()]
two = [(), ()]
three = [(), (), ()]
four = [(), (), (), ()]
...
concatenation `(++) :: Natural -> Natural -> Natural`: >>> four
[(), (), (), ()]
>>> three ++ one
[(), (), (), ()]
Your point still holds.Our (non-jargon) vocabulary simply isn't equipped to deal with this level of abstraction so we need jargon if we intend to be fully descriptive — existing words don't cut it and we are just at the bottom rung of the abstraction ladder.
It's up to us as a community how much we care about faithfully describing things, Simon Peyton Jones himself claims tongue-in-cheek that their biggest mistake was not calling monads “warm fuzzy things”[0] :)
[0] http://research.microsoft.com/en-us/um/people/simonpj/papers...
this would get downvoted quickly if it was a comment
A much better example would be "Show"(Showable) vs "Traversable".
If you really want to mess things up, use names that mean something different every day.
But I would know what a “Mappable” should be, regardless of PL.
Lots of terms like Profunctor, Contravariant Functor, Bifunctor etc. (which are also the names of typecasses in Haskell) rely on the precise, category-theoretical definition of Functor.
No, it has the same meaning. It does not behave identically because the languages do not have identical designs.
>But I would know what a “Mappable” should be, regardless of PL.
Lots of people wouldn't, and would be wondering what cartography has to do with anything. And even for people familiar with the functional "map", now they would just have an incorrect idea of what Functor is. Lots of Functors are things most people would not think of as being "Mappable".
> No, it has the same meaning. It does not behave identically because the languages do not have identical designs.
Functors in Haskell and OCaml are different things. Haskell Functors correspond to the category-theoretic notion of a functor (a thing mapping objects to objects and morphisms to morphisms in a reasonable manner). In OCaml and ML, Functors represent parameterized modules. These are not known to correspond to category-theoretic functors in any reasonable way (and there have been proposals for category-theoretic models of the ML module system). I guess the term Functor is a bit of a misnomer in the ML-like languages.
No, functors represent functions from a module to a module. Oh hey, that sounds just like the standard definition of a functor. As I said, the behavior is different because the languages are different, but both are named after the category theory functor, because they both emulate it.
http://cs.stackexchange.com/questions/9769/what-is-the-relat...
Functors play very different roles in Haskell and OCaml/ML.
In Haskell, the Functor class is there to implement the functoriality of a type. If F is a functor, then one implements maps of type F A -> F B from given A -> B in a functorial way.
In ML, the term functor was chosen because they are not first-class functions, but "a level up" (much like a functor is a level up from the maps in the category that it operates on). However, if F is an ML functor, then there are no "maps" between the modules F(A) and F(B). The morphism part, which is the essence of a Functor in Haskell, is missing in ML. This is why I think that the functor terminology isn't very good in ML.
Not everything that maps one thing to another is a functor.
Yes there is, the functor. Just repeating a false statement won't make it come true.
What we have is a functor F, which would be defined as in:
module F =
functor (X: S) -> ....
If you have two modules A and B of signature S, then you can form F(A) and F(B) and these are both modules. Now where are the maps from F(A) to F(B)? Just saying "the functor" does not explain this.> Just repeating a false statement won't make it come true.
Exactly!
If you want to claim a relation between OCaml functors and category-theoretic functors, then you must be able to justify your claims. Saying "functors represent functions from a module to a module. Oh hey, that sounds just like the standard definition of a functor." is just not a convincing argument.
That is literally the functor. Seriously, read the chapter on modules.
That would be an answer for Haskell (though a proper one would refer to fmap), but it does not work like that in OCaml. You do know some OCaml, right?
But if it's so obvious, then you can say how it works for the following concrete example:
module type S = sig
type t
val f: t -> int
end
module F = functor (X: S) -> struct
type s = X.t * X.t
let g x = X.f x + X.f x
end
module A : S = struct
type t = float
let f x = int_of_float x
end
module B : S = struct
type t = int
let f x = 2*x
end
module X = F(A)
module Y = F(B)
How do I get from X to Y by "literally the functor"?The point is: In the ML module system there is no equivalent to fmap: (A -> B) -> (F A -> F B), i.e. the functor action on morphisms. So, functors in Haskell and OCaml are different things. If you want to claim otherwise, you'll have to make an actual argument for it.
NB You only need to get from X to Y in ways that arise from getting from A to B. Since there doesn't seem to be any relevant concept of morphism it's hard to see how ML functors are anything other than trivially category theoretical.
E.g., "classOf fmap" as a synonym for Functor.
class (HasMap f) <= Functor f
class (Functor f, HasApply f) <= Apply f
class (Apply f, HasPure f) <= Applicative f
class (Apply m, HasChain m) <= Bind m
class (Applicative m, Bind m) <= Monad m
[1]: https://github.com/tfausak/purescript-neon/blob/v0.5.4/src/N...
[2]: https://pursuit.purescript.org/packages/purescript-prelude/1...Actually, I think there are three hard problems in CS. The third being pedants.