4 ms·
Looking through the really abstract scala code they linked brings up a problem that really frustrates me in haskell. Why doesn't anybody document their really a
by imh 10y ago
Looking through the really abstract scala code they linked brings up a problem that really frustrates me in haskell. Why doesn't anybody document their really abstract code? You know it's going to be confusing, so why not help out? If I have a type like
def foreignKey[P, PU, TT <: AbstractTable[_], U] ...
It's not sufficient to document the function's arguments. You also need to document the type variables! Likewise in haskell with code like
f . g x . (h (i x) $ j y z) . k $ aNamedVariable
It really isnt' so hard to refactor that into
let descriptivelyNamedFunction = (h (i x) $ j y z)
anotherDescriptivelyNamedVariable = descriptivelyNamedFunction . k $ aNamedVariable
in f . g x $ anotherDescriptivelyNamedVariable
It's much larger, but in certain places it prevents so many headaches. It's great that you can put stuff inline, but both communities seem super lax about accepting code that is the opposite of self-documenting.
edited for clarity, i hope
- runT1ME 10y agoWhat do you mean "document the types". They're type parameters... can you suggest better names for the parameters in StrongSyntax?
- imh 10y agoAs a small example, let's say I have a typed "agg" function with associated typeclass: class typedAgg t where agg :: t f r a b -> (r a -> b) -> f (r a) -> f b ... To lots of people, that's going to be really confusing. It might be easier if I document that f is supposed to be the type of the table, r is the type of the row, and a is the type of elements in the rows, if that's the intended usage.
- runT1ME 10y agoBut I'm saying, if you have a Higher Kinded Type like Strong, what do you name the variables? They don't refer to actual nouns. We're abstracted from that level.
- imh 10y agoIn my example, t, f and r are HKTs. Does that clear up what I mean at all? Strictly speaking in my example, f (r a) is the type of the table, but it's still illustrative to say that f is the type of the table, or say that it's probably a functor or at least similar to one. Specifically with Strong, I'm not sure what I'd comment, as I'm not that comfortable in Scala yet and don't know what Strong is. I'm not going to go digging around and there are basically no comments in that file, which is the problem I'm talking about.
- flukus 10y agoWould descriptive types help?: def foreignKey[PNamedType, PUNamedOtherType, TTlongTypeDescription <: AbstractTable[_], U] ... I know they help a lot in c#.
- fspear 10y agoThis is what I really hate about functional programming (specially Haskell), is almost as if the more obscure and unreadable your code is the more competent you are deemed to be.
- brangalina4eva 10y agoIt's like someone's run code through an obfuscator before committing.
- tel 10y agoI mostly agree with you, but I also think a bit part of what Haskell-like FP shows is how often your code is invariant to so many things that the variables no longer have any sense to them whatsoever. That doesn't really excuse badly named variables when that doesn't hold. It's more that it's something sort of novel to a lot of Haskell-like programmers and so we all get excited about it and probably overdo it somewhat. But on the other hand, I think it's very well-justified often enough. For instance, with class Functor f where fmap :: (a -> b) -> (f a -> f b) there are many words you could give to f, a, and b but they're essentially all misleading. With another example from the article, Strong Syntax, the "Syntax" bit is basically a convention in scalaz that ought to be immediately obvious if you're familiar with the scalaz library. The "Strong" bit has to do with a subtype of "Profunctor" structures, "Strong Profunctors". Profunctors are generalizations of functions that show up all over the place. Strong profunctors are profunctors which can "distribute over a tuple". Giving names to these types is an exercise in futility. At least with a function `a -> b` might be named `in -> out`, but with a Profunctor there isn't even that intuition. It's just too general. Subsequently, it shows up all over the place.
- aninhumer 10y ago> At least with a function `a -> b` might be named `in -> out`, but with a Profunctor there isn't even that intuition. What about: dimap :: (newIn -> in) -> (out -> newOut) -> p in out -> p newIn newOut
- tel 10y agoWith profunctors there's not necessarily anything going in or out and especially not necessarily and notion that the thing going in produces a thing going out. That's all roughly true with one kind of profunctor, a function arrow, but not true in general. For instance, data Counterexample a b = Cx (Set a) b is (very, very, very nearly [0]) a profunctor, but a isn't necessarily "going in" and b isn't necesssarily "coming out". [0] It's a profunctor if a is finite. You can handle the infinite form by writing it as `data Cx a b = Cx (a -> Bool) b` which is equivalent to what I wrote when `a` is finite... but it also makes it a little easier to pretend that a is "going in" even if that's a bad intuition.