8 ms·
While I really like these blog posts for keeping things light and intuitive, they're also sprinkled with claims that go a bit too far. > Arrays, Objects, M
by tel 7y ago
While I really like these blog posts for keeping things light and intuitive, they're also sprinkled with claims that go a bit too far.
> Arrays, Objects, Maps, WeakMaps, and Sets are all algebraic data types
This isn't really true on a couple levels. Algebraic Data Types are described through a small set of composition (data) or decomposition (codata) operations. Arrays, Maps, and Objects might be explainable in this way (though, really, we'd just be modeling them with ADTs). WeakMaps and Sets really cross the line though. WeakMaps, by their nature, need to appeal to something much more than just ADTs and Sets require "quotienting" to unify sets which contain the same elements in various ways. You can build the "raw stuff" from ADTs, but you won't have something that really behaves much like these types at all until you add in something extra.
The emphasis on sum types is huge, but it leaves out something critical: "JavaScript doesn’t have a lot of built-in features for sum types" is true of user-defined sum types (and related to it just not having types all together), but it has great support for a few special sum types: integers, booleans, characters! These sum types are important to talk about because it helps make clear that we already work with sum types all the time! Our basis for distinction and choice is built atop them in any language.
Finally, while products and sums get you some wonderful modeling capabilities, the place where Algebraic Data Types really shine is when you add two further capabilities: function types (exponentials) and recursion (fixpoint, which doesn't really map to high school algebra). Those are clearly built into JavaScript as well and would be great to discuss as well.
- nicoburns 7y agoI really, really hope JavaScript eventually gets support for: - User defined Sum types - Pattern matching on these Sum types in switch statements - Blocks and things-that-are-currently-statements becoming expressions that evaluate to a value. If it got those, then it would pretty close to the perfect dynamic language for me.
- agumonkey 7y agoConsidering TypeScript ~success, python type annotations and even PHP looking into sum types it's not far fetched to think js may adopt them.
- cies 7y agoSeen ReasonML? Pretty cool. Does that with a JS-y syntax.
- mc3 7y agoWhat is the benefit of pattern matching in a language where any value can be of any type at runtime? You can just pattern match by saying if (obj.type === 'foo') {}; if (obj.type === 'bar') {}; etc in JS, as long as you have set up the convention that you set the 'type' field, and practically this is just as good. The real benefit of pattern matching is the compiler checking at least that you have valid cases, and ideally that you haven't missed any cases.
- paulddraper 7y agoIt's more than that though. Scala example: myList match { case Nil => 0 case first :: Nil => first * 3 case first :: second :: Nil => first - second case first :: second :: rest => first * second + sum(rest) }
- thinkpad20 7y agoPattern matching goes significantly beyond checking “foo.type”. It adds the ability to specify exactly (as exact as the language and your data allows) what case you’re dealing with. For example, a list of length three where the first and last elements are empty strings. Having to specify this with a series of if statements often leads to verbose and error-prone code, but it’s trivial in a language like reasonml: switch (mylist) { | [“”, _, “”] => x | _ => y } Moreover, pattern matching usually involves pulling information out of the object at the same time. In the above example, maybe you want to do something with the middle element: switch (mylist) { | [“”, middle, “”] => middle ++ “!” | [“foo”, x] => String.reverse(x) | _ => “never mind” } All of this would be possible to do with a series of if conditions, but significantly harder to read and implement correctly. The power of pattern matching grows clearer as more complex data and rules are introduced. For example, it works just as well with nested lists: switch (mylist) { | [outer, [middle, [inner]]] => outer ++ middle ++ inner ++ “!” | _ => “never mind” } While having a type system is helpful in all of the ways a type system is generally helpful, there’s nothing about this code which wouldn’t also be handy in a dynamic language like JavaScript. For further evidence of this see Erlang and Elixir, dynamic languages which make heavy use of pattern matching. (Code typed on my iPhone so forgive the dopey examples)
- rectang 7y ago.oO( Just when you thought you understood algebraic data types, a real functional programming expert arrives to show you that you never will. )
- tel 7y agoDon’t mind my nitpicking. A huge part of algebraic data types arises from products and sums just as discussed here. As is always the case, there is hairiness between metaphor and precision, but presenting these ideas in JavaScript like this goes a long way!
- Quekid5 7y agoPlease don't do the "I'll never understand this" thing! Sure, it's possible that you never will, but mostly it's just about trying and practicing... IFAIUI the current scientifically supported thinking is that a good way to learn is to approach the subject from many different angles. Something to do with encouraging your brain to form lots of connections from different concepts to the concept you're trying to learn... I never thought I would understand point set topology, but for a few years I really did. (That was quite a few years ago, and since I haven't practiced... Well, it atrophied. Still remember my favorite proof, though! I also remember what a nightmare proof Stone–Weierstrass was :) ... amazing, but still a nightmare.)
- rectang 7y agoI actually have a decent practical understanding of sum types as they are used in Rust at least (including the tagged union implementation of enum). It's good enough to do useful work. Every time that functional programming patterns get discussed, though, there is a mad rush by functional programmers to impress upon everyone just how complicated they are. It is the same impulse that keeps the mathematical entries in Wikipedia accurate but utterly worthless for most people.
- Quekid5 7y agoAbsolutely, a practical understanding is enough. It also suffices for monads, monad transformers, etc. > Every time that functional programming patterns get discussed, though, there is a mad rush by functional programmers to impress upon everyone just how complicated they are. I... haven't observed this behavior personally. FWIW, I don't think that saying (for example) > Hey, we can actually define what "|" and "(_,_)" means in a mathematical way detracts in any way from a practical understanding. Can you elaborate on why you think it's detrimental? (I understand that it can come off as a little bit smug, but beyond that... meh?)
- AnimalMuppet 7y agoIn what sense are integers and booleans sum types? What is the definition of sum types that booleans fit? Is it just that it can be true or false, and because there's the "or", it's a sum type?
- chas 7y agoThe “or” makes it a sum type.
- AnimalMuppet 7y agoDoesn't that make everything (other than "bottom" or "unit") a sum type?
- Chinjut 7y agoSure, in the same sense that every set is a disjoint union over singletons of all its values. But whether you would or could naturally specify it that way or not depends on the set. You likely wouldn't sit down and specify the type "Function from natural numbers to Boolean" as a big OR over each possible such function, for example. But yes, whether something is a sum type or a product type or whatever is not generally so interesting as a predicate about the type in itself. It's a relationship between this type and other types. The same way it is not interesting to say "7 is a sum" (everything is a sum); what's interesting is to observe "7 is the sum of 3 and 4". [Disclaimer: In the same way that some topological spaces are connected and cannot be decomposed into separate disconnected components, one might sometimes reason that some types are connected and not reasonably represented as a disjoint unions over subtypes. So "Everything is a sum" is not always correct in all contexts. But let's ignore this sort of pedantry for now.]
- AnimalMuppet 7y agoHere's what's bugging me: Integers are a disjoint union of values, which is (in my non-abstract-algebra mind) something different than a disjoint union of types. That is, something like Maybe Integer is a "sum type" in a completely different way from the way that Integer is a "sum type". To me, this is different enough that a different term should be used. I'm sure you're going to tell me that I'm not thinking abstractly enough...
- Darmani 7y agoIndeed, maps and sets cannot be constructed from sums, products and recursion. They can be approximated if you throw exponentials in there. Instead, you can extend algebraic data types to combinatorial species, which do allow exactly the kind of quotienting you speak of. While they're unexplored in programming, they are believed to be programmable similarly to ADTs. https://repository.upenn.edu/cgi/viewcontent.cgi?article=1774&context=cis_papers https://repository.upenn.edu/cgi/viewcontent.cgi?article=177... I must take issue with the "objects are products" characterization you implied. Structures are products; objects need existential types: http://www.cis.upenn.edu/~bcpierce/papers/compobj.ps http://www.cis.upenn.edu/~bcpierce/papers/compobj.ps