Whether that's good depends on the problem... certainly SQL has been pretty successful.
Constraint based layout engines are such an example. Business rules engines are another. It's the fuzzy dividing line where we start considering programming techniques to be AI instead of conventional. This line is somewhat arbitrary based on history.
thank you, that seems to characterize it nicely.
Imperative programming spells out exactly what happens next; even if it's some high-level abstraction like "findAnswer()", that's still telling us what happens next, and we can jump to the definition of "findAnswer" to see what lower-level step comes next (and so on).
In functional programming, we're still specifying "what to do next", but we're allowed to give a set of things to do; the language accumulates these tasks, and is free to perform them in any order, or even concurrently; the result will be the same regardless (due to confluence). For example in an expression like 'f(g(x), h(y), [a(b), c(d), e])' we're telling the system exactly what to do next, although it's free to perform these function calls in any order it wants (many real implementations choose to define a particular evaluation order, to make e.g. reasoning about performance easier).
In both of these paradigms, the solution to our problem is left implicit: we indicate a solution by the lack of next-steps.
In logic/constraint/goal-driven programming the answer to "what happens next?" is undefined; we haven't told the system what to do next, so it's undetermined. Instead we've told the system when to stop: we make the solution explicit and the next-step implicit. The runtime system has to guess what to try, so it shuffles symbols around and around, stopping if it stumbles upon anything we've designated as a solution. Again, real implementations do define their evaluation order more explicitly for the sake of performance (e.g. depth-first search for Prolog).
- TK Solver [1] Once called "the crooked accountant's spreadsheet", it's a spreadsheet like program where you can change the outputs, and it will try to compute a consistent set of inputs. Good for "what if" problems.
- Kang. This was an early hacking program. It took a set of attacks, and given a starting state (such as "user not logged in") and a goal state ("kernel mode execution") would try to use its tools to reach the desired state.
- Map route finders. Specify start and goal, and a route is generated.
[1] https://www.uts.com/ItemDetails.asp?ItemID=0100-50-0010-00
On the other hand, I see the level of abstraction as (roughly) the average number of machine instructions executed for every statement or expression in the source language.
With these two definitions, its clear that while "declarative" languages will almost necessarily be at a high-level of abstraction, you can also have languages that operate at a high-level of abstraction without being declarative.
caveat: the original link wouldn't load for me, so I don't know if my response makes sense in light of the original article.
[0]a more technically correct definition is provided by David Barbour https://awelonblue.wordpress.com/2012/01/12/defining-declara...
Prolog is both abstract and declarative. Prolog programs are structured as a set of propositions (i.e. declarations). The difference between Prolog and Bash is greater than the difference between Bash and C, because the nature of Prolog implies a fundamentally different way of designing programs.
Rather than expressing how to take an arbitrary list and rearrange the elements so that they're sorted you express what means for a list to be sorted and let the algorithm figure out how to get there.
* An empty list is sorted.
* A single element is sorted.
* If one splits the list into its first element and its remainder then it is sorted if the remainder is sorted and the first element is less than or equal to the head of the remainder.
This doesn't lead to an efficient sort but it is enough for an algorithm to take any list and produce its sorted form. You can, with the right constraints, get a goal oriented system to carry just about every sorting algorithm and the benefit is that they're really concise and they read like the high level pseudocode you might see in an algorithms class.
It is calling the resolver system though and all the accompanying functions that actually do the sorting.
Not sure what is your definition of "source code", but I'm pretty sure nobody counts external library function implementations as source code for the program. Same as you don't count OS kernel as part of your program's source code.
It's not enough to express the desired result. We would also need to express our preferences for all the other decisions and trade-offs that are made during software development. Do we need this sort to be fast or use as little memory as possible? Synchronous? Does it need an index? Are we optimising for writes or reads? Persistence? What language are we sorting by?
That's for a simple sort. By the time you get into actual problems then it all gets more complex and the trade-offs become something you need to understand before making a decision on. Having an expert to make those decisions is good.
Are there languages that could take this and do merge sort?
* The resulting list must be a permutation of the original list.
It'd be kind of like test-driven or behavior-driven development, except that the programmer only writes the test cases, and the programming environment generates a program that passes the tests.
That capability would be more than just another rung up the abstraction ladder.
Interestingly, the problem of reasoning about programs at that level seems to be pretty nearly "AI-complete". This is true even though it's a formal domain -- one doesn't need, for example, the intuitions about the behavior of physical objects that we humans acquire through years of experience, nor an understanding of human behavior and emotions, etc. etc. We work pretty hard to make sure the behavior of a program is predictable just from understanding the program itself (there are occasional exceptions, of course). Yet even reasoning in such a restricted domain, about even very pedestrian programs, is beyond the state of the AI art at the moment.
The way I think of declarative programming is that it's essentially executable data; not in the manner of lisp, but a description of the problem space (usually as a set of constraints) is translated (compiled, if you will) into an execution plan that satisfies the description.
Declarative programming is the region where you've crossed the (fuzzy) border from eliding the small hows (e.g. memory management) to the big hows (e.g. the order to build components).
At a certain point, enough of a difference in degree changes the way you express a problem or thought, and at that point it's become a difference in kind. A loose aggregate of sand eventually becomes a pile when you've added enough.
A great example of transferring between problem domain language and implementation language is in game scripting. The game might have internal stuff for allocating actors and giving them various attributes, with asset references, state machines, etc. But when you go to script your behavior what you want to work with is "do this sequence of events in order, sometimes pausing, interrupting or branching it." And while you can do this by formalizing a new state machine each time, that's actually too powerful an abstraction to use to populate a script-heavy game full of one-off cutscenes, and many games will therefore go domain-specific and create a special cutscene system that limits the range of programmability.
So what I see goal oriented programming (and related ideas like model-oriented or intentional programming) arguing for is more along the lines of "principle of least power" - instead of wielding the most powerful abstractions directly, you invent a less powerful one to drive them, often compiling from less power into more power as a build step.
This is different in nature from high level abstractions intended to add more general-purpose leverage and user control over the problem definition, which garbage collection, metaprogramming, and formal-proof tools aim for.
There are many problem statements which operate on constant memory or employ a predetermined set of algorithms with known memory usage patterns, and they might employ one or more of these high level leverage tools as an intermediate to compile the definition to running code, without the user model or the runtime model needing them.
But it sounds like something I experienced before. You struggle to try to understand what this "new" thing is that's hot and it doesn't seem new to you at all. It frustrates you as you see other people talking about it excitedly and you feel like you're missing something. In my experience that's all it is. It's not new but a different spin on a long established and understood concept.