Does it? Maybe it's the way I think, but I have observed that I could move faster when the compiler is strict, because I don't have to think about whole classes of errors—they're automagically checked.
I like my compiler to be disciplined, so I don't have to.
Still, for example - I can see that dynamic types reduce a certain quantity of boilerplate. If you just don't make the kind of mistakes that make static checking necessary, then you could be more productive that way. I think a lot of boilerplate stuff is a bit like that.
I wouldn't be - but still.
Boilerplate isn't the reason why static typing might be worse than dynamic typing. Undecidability is. Inference algorithms tend to reject some correct programs. The real question is then, are we interested in those programs? So far, my experience has been "not really". I know of a few cumbersome exceptions, but overall, Hindley-Milner type inference basically lets me write the programs I want.
It's not like Java is a worthy ambassador for static typing.
I know it's not as much of a big deal in Haskell where mutable state is limited, but I still remember it being an annoyance to have to manually breakfast out my data to disk and then reload it again.
A good example is "variadic" functions. Consider computing the max of three numbers. Clojure's `max` takes any number of arguments, while Haskell has `max` that takes two arguments, or `maximum` that takes a list of arguments; both require some boilerplate to apply if you have exactly three.
It's impossible to write down a Haskell function equivalent to Clojure's `apply`. You have to work around its absence, e.g. with awkward folds.
Or for a more immediate example, compare Clojure's flexible `map` to Haskell's big 'zip' family: zip1, zip2, zip3, zipWith5...
max [a, b, c]
to be boilerplate.The whole concept of an `apply` function is a bit alien to me. I generally just call the damn function. Also, Haskell has an `apply` function. It's the `$` operator, defined thus (the first line is optional):
`$` :: (a -> b) -> a -> b
f $ x = f x
It helps that Haskell functions all have one argument (that with being curried by default). If you want several arguments, just apply them one by one: f $ x $ y
(This is sometimes used to avoid parentheses in some cases. I personally tend to just use the parentheses.)Well, you have to select one of the zip functions in addition to map. Those are more names.
> Also, Haskell has an `apply` function. It's the `$` operator
That isn't what apply does. Apply takes a function and applies it to a list of arguments, (f x y) is equivalent to (apply f (list x y)).
And the way to translate that in Haskell is to apply a single argument.
Haskell functions are not Lisp functions. Lisp functions take a list of arguments, so `apply` should apply to a list of argument. Haskell functions have one argument, so `apply` should apply to a single argument. That argument could be a tuple, by the way.
I understand how currying works, thanks, but that doesn't change the fact that $ is not equivalent to apply. A version of apply that dealt with curried functions would just have to fold over a list, and I don't think it could be properly generalised in Haskell's type system (but I"m not an expert at Haskell).
For your definition of apply, Lisp-1's don't have it, because as you said, you'd just call the damn function. Lisp-2's sort of have it, but it's called funcall. Regardless, your definition of apply is not what apply is in Lisp.
You are seeing that a square hole isn't fitting a round peg, and accusing the hole of being too sharp. Or at least millstone did. Complaining about the absence of a Clojure like `apply` function in Haskell doesn't make any sense.
It would be like complaining about having to work around the lack of infix notation in Forth. Whoever does that need to let go of their old thinking habits, and rewire their brain to the new language. Not everybody can do that. Fewer still want to do that.
Now if someone says, "this real world problem is easier to solve in Clojure, in Haskell you have to jump through hoops", that would be different. For the present case, one would have to show how the absence of a proper Clojure like `apply` function could force anyone to jump from any hoops to solve any concrete problem.
> Regardless, your definition of apply is not what apply is in Lisp.
You've either said too much, or not enough. What "apply" does mean in Lisp, then?
apply :: Dynamic -> [Dynamic] -> Maybe Dynamic
apply fn args =
foldM dynApply fn args
Impossible may be strong misclassification.But there are many language level tools that will help with your productivity. Some are all upside things, others come with different trade-offs. The article isn't even focused on compile-time verifications.
This was safer for pointy haired bosses :)
But that was at a time when more people learned Lisp, there was less choice in tools and the eco-systems were smaller. In the 70s/80s one could buy ten years into the future with the right hardware/software and government/military was financing.
Take for example the Connection Machine CM 1, an early massive-parallel computer with 2^16 processors. It was initially developed largely for and with Lisp. You could program it in *Lisp from a Lisp Machine - one of the most expensive co-processors. Fortran and C was added then for certain commercial users. Very expensive stuff and at least ten years ahead.
Today the landscape looks different.
The Objectstore database was developed by former Lispers, who wrote an earlier object-oriented database in Lisp.
You can bet this was simply due to lack of Lisp developers at Yahoo. And I can bet that the Lisp code was easier to read.
I once delivered a sophisticated pricing modeler to a financial institution, in Python, done mostly in functional style. Code well documented and commented, and easy to understand. And Python is one of the easiest languages to learn.
The customer's IT deparment insisted on a complete rewrite to Java, because that's what their developers knew.