5 ms·
I understand your point, and perhaps we don't actually disagree on this. As an example, in Haskell (which you have shown in another comment that you are familia
by clusmore 10y ago
I understand your point, and perhaps we don't actually disagree on this. As an example, in Haskell (which you have shown in another comment that you are familiar with), this function would perhaps best be written as
sum_and_stringify :: (Show a, Monoid a, Foldable t) => t a -> String
sum_and_stringify = show . foldl mappend mempty
In this case there are additional rules (semantics, though not in the language) which we associate with monoids like associativity that don't apply to all "addables" (e.g. strings), that might make us feel more comfortable being so general. I think really it's just that we have more expressive language to describe our expectations. Though there's nothing stopping you from making String an instance of Monoid, or most any type for that matter, and producing nonsense. It's not a type error, so I say it's (in this case) not the job of the type system. But there are more expressive type systems that could let you guarantee these additional properties like associativity and turn nonsense into type errors, and I for one am all for that.
In the case of Python, though, coming from no static type system or verification at all, I would only ask of this tool to turn runtime checks (type errors caused by arguments lacking __iter__ or __add__) into static checks. Anything on top of that would be fantastic, I agree with you on that, but I wouldn't ask for or expect it.
Finally, thanks for all your comments - I appreciate the discussion.
- dllthomas 10y ago> Anything on top of that would be fantastic, I agree with you on that, but I wouldn't ask for or expect it. Ah, we probably do agree more than it seemed. "The MyPy team has done its job even if that's not possible/reasonable" is a statement I'd endorse - especially in the short-to-medium term. Discussing the Haskell... String concatenation actually does associate; in fact String does form a Monoid over concatenation, and has an instance visible from Prelude - specifically the list instance, because Haskell strings are just `[Char]`. The only really "nonsense" thing about using a string here that I see is that we wind up with quotes and escaping in the result when we `show` the string. If the purpose of this is "gather results and format for logging", that might be fine. Numeric types don't have an instance of Monoid, because there are two to pick. You can pick them with newtypes, but here that's a bit awkward (`sum_and_stringify . map Sum`? feels redundant), and then the Show will give you something like "Sum { getSum = 3 }", which is probably not what you want either... Using Num rather than Monoid probably has better ergonomics, and may be closer to intent anyway. That is to say: sum_and_stringify :: (Show a, Num a, Foldable t) => t a -> String sum_and_stringify = show . foldl (+) 0 Of course, we have a `sum` defined (basically, perhaps literally) `foldl (+) 0` so why even pull this out into a function? `(show . sum)` is actually substantially shorter than `sum_and_stringify` and no less clear. I think the biggest issue here is that the example is so devoid of context (probably necessarily) that it's hard to say what good style would be. In actual code, a function with that name should probably have a very general signature - but we likely shouldn't be writing a function with that name. Why are we wanting to "sum and stringify" as one action in this way? Is that something that might change? Will the uses want to change together or are we just Huffman coding? With a domain-relevant name, we'd have a sense of what ways it makes sense to restrict the types. > Finally, thanks for all your comments - I appreciate the discussion. Likewise!
- clusmore 10y ago>String concatenation actually does associate; Oh my goodness, my brain exploded apparently because I meant to say commute, although commutation is usually not something to be expected of monoids. >Using Num rather than Monoid probably has better ergonomics, and may be closer to intent anyway. You're probably right on this point, in all honesty. I think I'm over-generalising the original intent. >With a domain-relevant name, we'd have a sense of what ways it makes sense to restrict the types Yes, I think this is the classic helper function vs library function quandary. If you wrote it to help yourself right now, it's often good to be very specific with the name and signature. That way if later you need to add more functionality you can without changing the name or restricting the signature. If you wrote it as a library function, it's good to be generic, to let as many people use it as possible. And in this case there should never be a need to change the function, it does what it does. If you need something else you just create something else.
- dllthomas 10y agoThis resonates with some things I've found myself saying recently around misunderstandings of the DRY principle. It's so catchy an acronym, and so seemingly self-explanatory, a lot of people don't realize it was originally framed in terms of knowledge, not syntax. So if syntax happens to be the same in N places, but in each of those places it is the way it is for a different reason, consolidating may not be "DRYing up the code". On the other hand, if I need to say "there's a text field here" in my markup and also in my logic, that could be more DRY even though the syntax looks nothing alike. Tying this back here, we find as a corollary: when factoring out code we can ask ourselves "what piece of knowledge does this represent?" If it is knowledge about the language (this is a good way to sort things) it probably goes in a library, and should probably be very general. If it is knowledge about your domain (this is how we escape HTML), it probably goes in a domain-specific library, and it should probably be somewhat less general. If it is knowledge about your application, it probably goes in your application or an application-specific library, and should probably be pretty specific.