4 ms·
Okay, before I say 'you win', can you show me this in Haskell: ; -- the program -- (defn add* [x y] (+ x y 1)) (add* (read) (read)) ; -- repl de
by wellpast 9y ago
Okay, before I say 'you win', can you show me this in Haskell:
; -- the program --
(defn add* [x y] (+ x y 1))
(add* (read) (read))
; -- repl demo --
3
40.1
44.1
- wellpast 9y agoI'm going to assume that if you take 10 times longer to respond to this than it took me to respond to you, then my "orders of magnitude" claim has been proven. (...friendly joke, of course.)
- tome 9y agoIf using Clojure means that one no longer needs sleep then I concede immediately.
- danwilsonthomas 9y agoI tried this, because my first thought was that this was much the same as the first example. Certainly Haskell doesn't have a variadic addition function by default but I don't think that's the biggest concern here (variadic addition is easily just summing a list). The surprising thing was entering both an "integer" and a float to be read. You certainly can parse floats from input, but this: `(+) <$> readLn <*> readLn` doesn't do it, even though at first glance it seems like it should. If you wanted to handle fractional values, you would have to hint to the type checker that you wanted to do so. I do think that this example is perhaps too specific, and highlights only the specific topic of dynamic number conversion which is, depending on the situation, both blessed and cursed. I will concede though that if you want dynamic number conversion Haskell isn't going to give you that easily.
- tome 9y agoGHCi defaults to numerical operations on Int by default, so we have to specify what type we would like. Before you convince yourself that that's an obvious loss for Haskell bear in mind that you have to specify the type at only one single place in your whole program and it will propagate everywhere else, even if your program is 10m lines. Prelude> add_ x y = x + y + 1 Prelude> add_ <$> readLn <*> readLn :: IO Float 3 40.1 44.1
- wellpast 9y agoBut this is the point. My Clojure program is valuable/effective/per-spec without the type burden. So the type burden has slowed my delivery. And that "one single place" is for this trivial toy program. Now imagine the impedance across the delivery of a real business app.
- danwilsonthomas 9y agoI was thinking about this sentiment: And that "one single place" is for this trivial toy program. Now imagine the impedance across the delivery of a real business app. That seemed very incongruous with my experience. I think the problem is that in my experience the number of types necessary scales sub-linearly with the amount of code. This is because Haskell (and other languages with what one might consider pleasant type systems) generally have full type inference. So while you might need the explicit type for the toy example, scaling that example up means only a handful, and possibly a net negative, other necessary explicit types. This comes up in a concrete manner in your example. The add function is almost too small to be typed appropriately. There isn't enough information for GHC to constrain the choice of numeric representation so it picks one. If you were to embed that in a larger program with more specific operators no types are necessary. Prelude> let add = (+) <$> readLn <*> readLn Prelude> let foo = (/) <$> add <*> add Prelude> foo 3 30.1 40 10.2 0.6593625498007968 So it's quite possible that the "type burden" becomes smaller as your system grows.
- tome 9y agoReally nice observation! Thanks.
- wellpast 9y agoWhat you did here is very opposite from what real-world dev looks like. Here, you picked a `foo` so that the type checker could find consistency. Typically in the real world, the customer or product manager asks for the thing-of-value. The job is not find a `foo` that reduces the type annotations. The job is to add business value to your system, to your code. The probability that the world asks for something that fits so nicely into your type taxonomy is low. The real world and the Future is often more creative than our invented taxonomies support. In these cases, what you need to do is go fix up your types/taxonomy so that consistency ensues again. Whether or not that results in less type annotations doesn't ultimately matter. It's the work you had to do (the game you had to play) to make the type checker happy. Note: The implicit assumption behind what I'm saying is that we want to create less work for ourselves, not more. If we don't care about work/time/efficiency, then my arguments in this thread are all moot/baseless.