7 ms·
Very good, although I thought the dynamic typing one was a bit snarky. I'll happily give up dynamically typed languages like clojure when structural typing can
by joncampbelldev 9y ago
Very good, although I thought the dynamic typing one was a bit snarky. I'll happily give up dynamically typed languages like clojure when structural typing can give me the same flexibility.
I say this as a person learning idris and Haskell and loving it btw, before anyone prematurely tries to convert me to static typing.
- tome 9y agoAs a Haskell proponent I'd be really interested to hear specifically what it is that you'd like to do in Haskell but can't.
- rrobukef 9y agoOpen type variation require existential types. Not the easy types people are used to.
- tome 9y agoCould you explain what you mean by "open type variation"? Google's throwing up nothing relevant ...
- Ace17 9y agopolymorphism?
- tome 9y agoI don't think that can be it. Polymorphism doesn't require existential types!
- rrobukef 9y agoClosed polymorhpism can always be pattern-matched but it requires modifying all matchers. Open polymorphism is the default in OO interfaces: you can always implement a new type by adding code locally. Since existential types can be monomorphised and compiled to binary code allowing type-safe plugins.
- Ace17 9y agoYeah, I was referring to polymorphism as we have in OO, where old code can call new code. I didn't even know "closed polymorphism" was a thing (is it equivalent to algebraic types?).
- rrobukef 9y agoI'm not precise anymore with jargon concerning polymorphism (it's all the same to me), which I probably shouldn't do. I consider two factors: first closed/open (or finite/arbitrary) of 'remembering' an erased type, and second the sugar for nested 'remembering'. Almost all languages have both (open and closed) as either built-in, as a library or as a design pattern for that language. It boils down to either a tagged union or a function pointer. And both can be transformed to the other if needed. Assembly, C have tagged unions & function pointers. Java has visitors, instanceOf, reflection. C++ has visitors, boost::variant, dynamic casts, mach7. Haskell has ADTs, pattern matching, existential quantification, Dynamic. Rust has pattern matching, traits, Any. Python, javascript, lua, lisp are dynamic, it's easy enough to create both.
- JadeNB 9y agoI think it refers to open unions, which are types specified with some constructors that might have additional constructors defined later. As you say, Google is curiously reticent, but see, for example, p. 60 of http://www.seas.upenn.edu/~cis500/cis500-f06/ocaml-book.pdf http://www.seas.upenn.edu/~cis500/cis500-f06/ocaml-book.pdf .
- rrobukef 9y agoSorry for the confusion, JadeNB is correct: open type unions. For when you want plugin-like code without significant recompilations.
- tome 9y agoOK, fine. Well in Haskell we have Dynamic. Of course matching on a Dynamic may fail, but that's OK because the basis for comparison is untyped languages! Matching on types can always fail there too.
- rrobukef 9y agoWith Dynamic, yes, but not with existential quantification. The type is a proof the type-class is implemented. I also didn't yet know Dynamic, thanks. I'm not that fluent in fp.
- deleted 9y ago[deleted]
- shakna 9y agoWrite a program that anyone can read. Haskell inevitably ends up looking more like a mathematical equation than the simpler constructs people are more used to finding in languages like Clojure.
- tome 9y agoThat may or may not be so (my contention is that it is not so) but that's another debate. The question I'm interested in finding the answer to is specifically what important things you can do in Clojure but not Haskell because of Haskell's static types.
- shakna 9y agoWhat can I do in Haskell that I can't do in Clojure, because of Clojure's dynamic typing? If you want to add static typing, you're looking for a contract library. Some are runtime, some use the macro system to get compile-time checking. (In fact, core.typed looks almost exactly like Haskell type definitions.) If you miss Haskell's pattern matching, you can find it at core.match. You want monads instead of variadic functions? Nothing easier. Laziness is a lambda away. Clojure, and so many similar dynamic languages have the power to give you the safety of static typing, if and when you want it. But they don't require it of you. In some cases this can be bad, when you don't think through your data structures enough. In other cases, it can be good because you don't need to think as much as you put things together, and can go back and expand later. I think every language has a time and a place, for the right purpose.
- tome 9y ago> What can I do in Haskell that I can't do in Clojure, because of Clojure's dynamic typing? Also an interesting question, but, again, not equivalent to the one that I asked! joncampbelldev very specifically said that Clojure gives him more flexibility than Haskell. I'm asking for specific examples, otherwise how else can I improve Haskell or its documentation to be more appealing to fans of dynamic languages?
- 9y ago
- PeterisP 9y agoBe able to clearly reason about the space complexity of code. Even quite short parts of code can have an unexpected (at least unexpected to me) explosions of thunks, and it's quite difficult (at least to me) to find out where/how strictness markers should be added so that the code wouldn't generate the totally unneeded gigabytes of temporary data that I see in the memory profiler. It's quite easy to reason about the correctness and results of Haskell code execution, but it's hard to reason how exactly that code will be executed in ways that have an extreme effect on performance - not tenfold, but e.g. exponential relative to dataset size.
- tome 9y agoAnother worthy topic of debate that is completely unrelated to my question. Types and laziness are independent -- at least to the degree needed to provide an answer to my question.
- jack9 9y ago> Types and laziness are independent I think they are directly linked. If I have to worry about arbitrary types, my code can never be robust for the environment it runs in without raising some generic exception. This is the lazy approach. In a dynamic language, everything can be boxes to a static list of flexible types and is by default, meaning my code is succinct. This doesn't address the question (which is a strawman), but is the heart of the debate about static vs dynamic typing. Getting things done faster (with some guarantees) vs many guarantees (but not all) at a slower rate of progress (because you have to essentially duplicate code at a higher level, that the dynamic interpreter is already doing).
- tome 9y agoI can't actually understand anything you've said. You are using this definition of lazy, right? https://en.wikipedia.org/wiki/Lazy_evaluation https://en.wikipedia.org/wiki/Lazy_evaluation
- z1mm32m4n 9y agoThat's not true. When the language is lazy, you can't give a different type to one expression that's lazy and one expression that's strict. You can write hacks into the language that tell the compiler to evaluate certain expressions strictly, but you can't capture this in the type system when the language is lazy by default. On the other hand, this is perfectly possible in a strict language.
- falcolas 9y agoExploratory coding that doesn't require tree-shaking refactors when a type needs to change. "The spec changed, and I now have to be able to handle geese, where I originally typed for ducks." There are ways and tools to minimize the impact, but it's still a lot extra overhead to think about and deal with.
- tome 9y agoAha! The first reply that actually provides an answer to my question. Many thanks. Could you say any more about this, or perhaps provide an example? Its hard to know what you mean. EDIT: Attempting to answer my own question, perhaps it occurs when you define a product type with a constructor data Foo = Foo bar baz and then you want to add a new field to Foo data Foo = Foo bar baz quux All your explicit uses of Foo in construction and pattern matching have now broken.
- PeterisP 9y agoFrom the type perspective, one challenge is processing data where you don't know and don't care what types and what structure parts of that data will have. One domain is deserialization of json or xml in a way that's agnostic to the structure of any extra data that I'm not explicitly referencing. For example, if I want to take a structured message (json or xml), do computation on parts of that message (so I need to decode these parts to "normal" data structures), and create a modification of the original message where my results are added but everything else is unchanged. The last time I had to do this it was a bit painful as the serialization/deserialization libraries (I don't even recall which I used in the end. aeson? I tried a bunch.) expected me to know/define the whole structure if I wanted to properly serialize the updated data afterwards, and would break whenever the an updated api started returning a different message structure than expected (e.g. added new fields). Perhaps I didn't find the right tools/approach to do this, but it's a rather common need and doing the same is quite trivial in python/javascript/etc.
- z1mm32m4n 9y agoI've not found an elegant way to express in Haskell what can be expressed trivially with modules and functors in SML/OCaml.
- tome 9y agoAnother interesting point that is not relevant to the question I asked, which was about dynamic typing!
- mannykannot 9y agoThis quote riffs off the point that the issues of type are there whether or not your language requires you to be explicit about them. On the other hand, the empirical evidence for the effectiveness of static typing is weak. This may be because the latest developments in static typing have not found their way into mainstream languages, but that is only a conjecture. You may prefer this quote: "Static types give me the same feeling of safety as the announcement that my seat cushion can be used as a floatation device." - Attributed to Don Roberts by Martin Fowler.