> But it could be worse if the standard were "feature oriented" rather than eliminating the limitations and flaws by cleanly generalizing the model.
Why do you feel that "eliminating the limitations" is the way forward, and not standardizing common tasks instead, making them ergonomic, uniform, fast?
I don't think that more power can lead to those. Maybe ergonomics and uniformity can happen by accident if a library emerges as the default option for a task, but speed, I don't think it can.
> Prolog predicates are not first class values.
Predicates are trivially called, even as variables, with the `call/N` metapredicate.
> Mapping and filtering is awkward
In what sense? The declarative semantics...?
> Arithmetic is awkward
In what sense...? Have you seen clpz?
> The CLP examples aren't integrated with Prolog's Horn clause resolution model
In what sense...? clpz and clpb do this magnificently.
> Indexing and search strategies are not under programmer control.
Most ship with SLG resolution or you can write your own resolution strategy with a simple metainterpreter as an intermediate exercise -- but SLD resolution is already pretty good. In general not needing to think about the indexing and search strategies are a highlight of the declarative semantics of Prolog, its odd to see someone with a "long standing love affair with Prolog" list this as a drawback.
> Modes are awkward.
Modal programming is a defining feature of Prolog. Tell me more about this "long standing love affair", again?
> I've been an enthusiastic Prolog programmer since the mid 1980s
If you are still struggling with mapping, filtering, arithmetic, `call/N`, and CLP in Prolog after nearly 45 years of "enthusiastic" programming, I'd highly recommend checking out Triska's Power of Prolog videos for some guidance, I think you will find them very illuminating.
Yes, that is the definition of "predicates are not first class values". Some things can be called without call/N. Other things can not be called without call/N. These are two separate classes of things. Both of these classes cannot be the first class.
"First class" meaning, can be the arguments to a predicate or processed as data.
Predicates (and only predicates) can be called with `call/N` -- although you could write a meta-interpreter with different properties. You could pass in the number `1` and call a randomly determined predicate, as an absurd example.
Perhaps you mean, "the head and body of a predicate are not first class" ? This again is false. They are valid data and can be processed as such -- please see [4] for clarification.
Perhaps you mean "they cannot be looked up dynamically at runtime" -- this is also false, please see [3].
Are there other eligibility requirements for "first class" that we should discuss?
First class data, yes. First class predicate, no.
> Predicates (and only predicates) can be called with `call/N`
Some class of things that you apparently refuse to call "predicates" can also be called, but without having to use call/N.
> Perhaps you mean, [...]
No. I mean there are first-class callable things and second-class callable things, and second-class things are not first class.
However, this is a charitable interpretation that is open to abuse if desired.
It is starting to sound like the criticism is that Prolog is not an object oriented programming language and does not pass contextual object information along with symbols in the same way SICP-style higher order functions are treated in functional programming languages.
This is by design, Prolog is a logic language that describes relationships, not a procedural language.
There is no behavioral difference that distinguishes a Prolog predicate as not "first class". There are many metapredicates designed to accept predicates as arguments, such as maplist/N. This is the primary criteria for supporting first class "callables" (another word poorly suited for Prolog, but I'm admitting it for purposes of conversation) in other languages. I would have assumed that would be a sufficient behavioral affordance.
> there are first-class callable things and second-class callable things
To make this more concrete, please provide some examples of "first-class" and "second-class" "callable things" in Prolog, as well as an example of "first class" and "second class" "callable things" in another language.
Given your level of confidence in your argument, I assume this should be fairly easy to do. Then we might have a concrete basis for discussion.
Not for you, but purely for the benefit of unfortunate souls who wander by and are confused what there is to argue about:
call_direct_and_indirect(IndirectCallTarget, Input, Result) :-
call_direct(Input, Intermediate), % first-class call
call(IndirectCallTarget, Intermediate, Result). % second-class call
This predicate calls some other predicate `call_direct/2` in a first-class way. It's a call.It also calls some predicate identified by whatever the variable IndirectCallTarget may be bound to. This is a second-class call. It's frequently referred to as a "meta-call" to signal that it's not a first-class call. It's important to note that the value passed in for the IndirectCallTarget parameter is not a predicate. It cannot be, since there are no predicate values in Prolog. It's the name of a predicate. (Plus maybe a partial argument list; still not a predicate.) Since the thing being meta-called is not a predicate, it must be meta-called specially using the `call/N` builtin. The user has no realistic way of implementing the `call/N` builtin themselves.
Not sure what you mean by realistic, but `call/1` can be implemented by having one simple rule for each existing predicate (now for the sake of the argument ignoring control constructs, which require somewhat more complex processing first) plus a rule for uninstantiated variables and one for an inexistant predicate. And `call/N, N > 1` can now be defined based on it.
Of course you wouldn't really need to enumerate all predicates in the definition of call/1. You could first run a whole-program abstract interpretation to identify just the ones that can actually be meta-called. Much more appealing :-)
> call_direct_and_indirect(IndirectCallTarget, Input, Result) :- call_direct(Input, Intermediate), % first-class call call(IndirectCallTarget, Intermediate, Result). % second-class call
I see we are at an unfortunate impasse. I assert what you are calling a "second-class call" is usually considered "first-class". I will leave the definition here for readers to decide for themselves. I rest my case and wish you a good day.
https://en.wikipedia.org/wiki/First-class_function
> Higher-order functions: passing functions as arguments
Further information: Higher-order function
In languages where functions are first-class citizens, functions can be passed
as arguments to other functions in the same way as other values (a function
taking another function as argument is called a higher-order function). In the
language Haskell:
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = f x : map f xs