|
This is solved long ago, without taking any extremes. In short, a language should be mostly-functional, which means when you really need to overwrite a value you just do it. In well-researched languages, such as Scheme you have set!, in CLs you have setf. All the monadic stuff (remember, that a monad is nothing but an ADT - Abstract Data Type) is already an extreme, because one must structure the code in a certain way. However, one could write monads in Scheme, there is absolutely nothing special about them. I think that monad madness it is of the same nature as over-engineering madness that plagues OOP - wasting of time and effort on construction of vast, meaningless class hierarchies. On the other hand, to find a balance is the most difficult task. Scala, it seems, is close enough, but the ugliness of static typing - parametrized types polymorphism is still here. On the other hand, it avoids mutation whenever possible, uses persistent data structures and first class functions, which results in a much more reasonable and predictable, and, as a consequence, reusable and manageable code (modularity with almost no side-effects). Yet another point is that there are literally tens of implementations of OOP features for CLs and even Schemes, which might suggest to you that OOP is just a set of conventions and rules - how to reference and dispatch methods - nothing but pointers and procedures, which are the most fundamental abstractions in CS. The big ideas from Lisps, like everything is a reference, values have type (tags) not variables (you don't need Nothing to be a subclass of everything,) together with first-class functions without side-effects is that good-enough set of features for a programming language. The point is that so-called "best of the both words" was discovered long ago in classic Lisps and it could be loosely called a mostly-functional language. |