4 ms·
The problem is programmers crafting the language to their own mental model. One solution is languages that don't allow much abstraction. The other solution is t
by noelwelsh 7y ago
The problem is programmers crafting the language to their own mental model. One solution is languages that don't allow much abstraction. The other solution is to craft a shared mental model. This latter approach is the more powerful in my opinion.
Taking the example of adding maps, you (where "you" means the language designers or language community) just need to define what `+` means for primitive types and the composition follows naturally. What does adding maps mean then? It means adding together the primitive types found under each key. If everyone agrees 1) there is a `+` operation and 2) what it means for primitives, there isn't much room for confusion. At some point you might want to give this concept a name and then you have basically reinvented monoids.
This is one of the differences between my experience in untyped functional languages (primarily Scheme) and inexpressive languages (primarily Java) and typed functional languages (primarily Scala). In the former each abstraction was a perfect snowflake crafted to the specific situation. In the latter we just reuse existing abstractions. The problem with the former is you have to learn the meaning and idiosyncrasies of each new abstraction. In the latter you can leverage your existing knowledge in new domains.
- chrisweekly 7y agoI can't parse your last paragraph, in which "Scheme and Java and Scala" (3 things) are compared as "former vs latter" (2 things).
- noelwelsh 7y agoMy bad, I missed a comma. The former is Scheme and Java. The latter is Scala.
- AzzieElbab 7y agoWrt to code sample in the original article, are you saying live would be so much easier if everyone knew what monoids are?
- noelwelsh 7y agoSaying life would be "so much easier" seems like a strong statement, but I expect programming would be. :-) When I read that example the semantics were obvious to me: adding a map (applying a monoid operation on a map) should add the elements (apply the monoid operation for the elements).
- oddthink 7y agoBut one of the examples of adding maps would be for it to mean "upsert", rather than "use the monoid for the value types". I think that's still a perfectly good monoid over maps (it's not commutative, but that's not a requirement). And yes, you can argue that using "+" implies commutative, and I can see that, but I think it's still a plausible meaning in this context. (I'm probably rabbit-holing here, but it's interesting.)
- noelwelsh 7y agoHow you handle this gets into the details of the programming language used for implementation. The usual implementation technique is type classes, and the issue of having multiple type classes (implementations of, say, monoid) for a given type is known as "type class coherence". In Scala you could just pass a type class instance explicitly. If Haskell you'd have to change the type.
- hinkley 7y agoI’ve heard one of the early Agile luminaries say that if the terminology in your code is different than the terminology of your domain that it’s a code/design smell. Some day, if not already, that impedance mismatch will bite you in the ass. Architectural astronauts are fond of their own terminology. It’s nuts. Especially if it’s from someone like my most recent perpetrator who tries to use big words all the time and either gets them wrong or uses obscure meanings that nobody else ever uses conversationally. You may be smart pal, but you’re the biggest idiot I know. At least the last astronaut was personable and had a hint of humility.
- Terr_ 7y ago> if the terminology in your code is different than the terminology of your domain that it’s a code/design smell. Hence the idea/label of Domain Driven Design [0]. IMO like unit-testing it's valuable but you can't hope for 100%. There will always be some concepts that are unique to how the data is being packaged or calculated which aren't part of the business-domain, but hopefully they'll be safely locked down beneath domain-centered abstractions. [0] https://en.wikipedia.org/wiki/Domain-driven_design https://en.wikipedia.org/wiki/Domain-driven_design
- pron 7y ago> One solution is languages that don't allow much abstraction. I think we need to be careful here with what you mean by "abstraction." One kind, which we can call "syntactic abstraction" means the following: given a specific language, what portion of its syntactic patterns can be factored into a new construct that "abstracts" all of its instantiations. Languages with macros score very highly here. Another kind, which has been more studied mathematically, is what we can call "algorithmic abstraction" or "behavioral abstraction", which means that given a certain specification of a desirable observable behavior, what portion of the implementations of that behavior can be exposed with the same syntactic construct (the same API). On this front, Haskell has worse abstraction than Java (e.g. if you want to change the implementation of a map to support big data with disk writes, you have to change the syntactic construct), and a language like Rust has terrible algorithmic abstraction, as even different implementation details like memory lifetimes require different constructs. Every additional piece of implementation detail that is exposed in the syntax level (e.g. in the type) hurts abstraction. I don't think that proponents of exposing as much as possible in the type think that's a bad thing, though. Both of these kinds of abstraction allow you to "leverage existing knowledge in new domains", and both have a certain "mental" cost. I don't think it is possible to relate "abstraction" in general to any bottom-line result, especially as no language choice seems to show any big impact one way or another, but mostly cater to different personal aesthetic preferences.
- marmaduke 7y ago> craft a shared mental model. This latter approach is the more powerful Isn't the crux of why programming is a technical activity second and a social one first?
- jart 7y agoNotation is the word you want. For example, we can design our language to say ht[x]=y or HashInsert(hTable,key,value), but at the end of the day they both abstract computer science toil don't want to think about, e.g. should it cuckoo probe pascal triangle bucket tree big theta under the hood yadda. My opinion is that terse notation only gains consensus when it's divinely inspired. That's the word we've traditionally used to describe the np-complete social phenemonon that happens every so often, where some guy's arbitrary mental model manages to allure a lasting self-evident appeal, e.g. LISP, C, and Python. So in some ways, we can think of guys like John McCarthy as modern programming prophets. One interesting thing I noticed, reading John McCarthy's original paper, is he was actually trying his darndest to not introduce a new notation. He wanted LISP code to look normal, since it's usually not a good thing to come across to other smart people as claiming divine inspiration (see Dunning Kruger). I disagree with the conventional wisdom though. If you'd want to take the more powerful approach of crafting a shared mental model, my advice would be one of encouragement. You can absolutely be the next John McCarthy. Folks only use wordy notation like HashInsert(hTable,key,value) because they want to go the safer route of being a small successful part of a large corporate machine.