Ukraine is poor. It is corrupted. Its population is declining.
It has a chance still: there is a social demand for a different lifestyle and organisation of the state, which eventually will solve many problems Ukraine has and will make it a place not worse that any other East-European country. Now it's on the way of building democracy and it may fail without help, unfortunately.
What we need from the West is constant pressure on our establishment to setup effective institutions, especially in the anti-corruption domain.
Source: I'm a Ukrainian still staying in Ukraine because I believe the above is true. Otherwise I'd move to EU with very little effort or to Russia with no effort at all.
Let me address your criticism from Scala's point of view
> they are very blunt
I'm more blunt than the complier usually. I really want 'clever' programs to be rejected. In rare situations when I'm sure I know something the complier doesn't, there are escape hatches like type casting or @ignoreVariace annotation.
> the problem of how to express your invariants within the type system
The decision of where to stop to encode invariants using the type system totally depends on a programmer. Experience matters here.
> Our program can't "pass through" this data from one end to an other
It's a valid point, but can be addressed by passing data as tuple (parsedData, originalData).
> What if there's a new Tag added? What if the Category tag adds a new field?
If it doesn't require changes in your code, you've modelled your domain wrong - tags should be just a Map[String, String]. If it does, you have to refactor+redeploy anyway.
> What about something like updating all updatable fields of an object
I'm not sure what exactly you meant here, but if you want to transform object in a boilerplate-free way, macroses are the answer. There is even a library for this exact purpose: https://scalalandio.github.io/chimney/! C# and Java have to resort to reflection, unfortunately.
where each method just returns Unit or throws exception? The version with IO/Future is superior since it at least explicitly states that you can get an error here. If you want to say that Go-style error handling is better because if forces errors handling, I can kind of buy it, but it also has some cost.
>You don't have while/if-else/etc
Maybe you are looking for ifM/whileM functions from e.g. here: typelevel.org/cats/api/cats/Monad.html.
> This is a fact-based discussion of language trade-offs.
I'm sorry, but it's an opinion-based discussion. No hard facts were presented here. While I see the reasoning behind such opinion, it directly contradicts opinion of pure FP proponents and somewhat contradicts my own experience.
> the business use case of that software suddenly demands incrementally mutating some part or introducing subtle violations of the constraints the system was designed to enforce
Sure, sometimes it's very convenient to add quick hacks, but there is definitely a tradeoff from maintainability perspective. I wouldn't like to work on a codebase full of mutable state and constraints broken in unprincipled ways.
On the other hand, I never used Haskell and religiously functional Scala, so maybe I underestimate the scale of the problem. For me Scala with immutable collections, ADT, lenses, IO, typealiases and typeclasses as extension mechanism served extremely well. Could you please provide few concrete examples of type system abuse?
Source: I'm a Ukrainian still staying in Ukraine because I believe the above is true. Otherwise I'd move to EU with very little effort or to Russia with no effort at all.