• Re: How Prolog became an education nightmare (Was: 50 Years of Prolog N

    From Mild Shock@21:1/5 to Mild Shock on Tue Nov 12 16:32:44 2024
    Here is the SWI-Prolog and the SICStus
    Prolog abstract parse term. This is the real
    nightmare of every computer science professor,

    who wants to use Prolog in a compiler
    construction course:

    /* SWI-Prolog 9.3.14 */
    end(end(begin(;(=(x,1),;(=(y,2),begin(=(z,3)))))))

    /* SICStus Prolog 4.9.0 */
    begin(;(=(x,1),;(=(y,2),begin(end(end(=(z,3)))))))

    On the other hand mostlikely the OP @horsh
    would expect:

    /* What the End-User wants */ end(begin(;(=(x,1),;(=(y,2),end(begin(=(z,3)))))))

    I think its impossible to do in any Prolog system,
    you would need a programming language with the
    possibility to do mixfix syntax definitions,

    like for example in Isabelle/HOL:

    (* Define the mixfix syntax for a Pascal-like block *)
    syntax
    "_begin_end" :: "'a ⇒ 'a" ("begin _ end")

    Or otherwise use DCG to write your own parser
    for the DSL at hand, that you want to parse.
    Since Prolog operators cannot model mixfix syntax,

    at least SWI-Prolog and SICStus Prolog fail,
    and I guess other Prolog systems fail as well.

    Mild Shock schrieb:
    Concerning the input (xxx yyy zzz) the OP wrote:

    I would expect it to print zzz(xxx(yyy)).

    Where did he get this requirement from, he didn’t
    compare other Prolog systems, right? So it came from
    his applicationdomain. But what was his application

    domain? Ok, lets proceed to an example with multiple
    brakets. Lets make the Pascal “begin” “end” example,
    by replacing xxx and zzz by “begin” and “end”.

    I get this result:

    ?- member(X,[begin,end]), current_op(Y,Z,X).
    X = (begin), Y = 1100, Z = fy ;
    X = (end), Y = 1100, Z = yf.

    ?- X = (begin
    |          x = 1;
    |          y = 2;
    |          begin
    |               z = 3
    |          end
    |       end).
    X = (begin x=1;y=2;begin z=3 end end).

    But is the abstract parse term, the Prolog result useful?


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mild Shock@21:1/5 to Typically we want to then go on and on Thu Nov 14 05:14:13 2024
    Lets cut through the thicket. There is no
    real world use case of a (fy 1 yf). Take again
    the Pascal “begin” “end” mixfix example.
    Typically we want to then go on and write

    for example a compiler:

    :- op(1100,fy,begin).
    :- op(1100,yf,end).

    compile((begin X end)) --> compile(X). %%% scoping omitted
    compile((X;Y)) --> compile(X), compile(Y).
    compile((V=E)) --> [load(E),store(V)].

    The problem is the pattern (begin X end) will
    not work, if multiple (begin … end) are involved
    in the compile/1 call. You can try yourself, no

    Prolog system can do it:

    /* SWI-Prolog */
    ?- X = (begin
    x = 1;
    begin
    y = 2
    end
    end), compile(X, L, []).
    false.
    %%% expected L = [load(1),store(x),load(2),store(y)]

    /* SICStus Prolog */
    ?- X = (begin
    x = 1;
    begin
    y = 2
    end
    end), compile(X, L, []).
    no.
    %%% expected L = [load(1),store(x),load(2),store(y)]

    The reason is that the parser will join multiple yf,
    similarly it would join multiple fy. The parser will
    not follow a braket pattern. At least I don’t know
    any Prolog system that can do it.

    Mild Shock schrieb:
    Here is the SWI-Prolog and the SICStus
    Prolog abstract parse term. This is the real
    nightmare of every computer science professor,

    who wants to use Prolog in a compiler
    construction course:

    /* SWI-Prolog 9.3.14 */
    end(end(begin(;(=(x,1),;(=(y,2),begin(=(z,3)))))))

    /* SICStus Prolog 4.9.0 */
    begin(;(=(x,1),;(=(y,2),begin(end(end(=(z,3)))))))

    On the other hand mostlikely the OP @horsh
    would expect:

    /* What the End-User wants */ end(begin(;(=(x,1),;(=(y,2),end(begin(=(z,3)))))))

    I think its impossible to do in any Prolog system,
    you would need a programming language with the
    possibility to do mixfix syntax definitions,

    like for example in Isabelle/HOL:

    (* Define the mixfix syntax for a Pascal-like block *)
    syntax
      "_begin_end" :: "'a ⇒ 'a" ("begin _ end")

    Or otherwise use DCG to write your own parser
    for the DSL at hand, that you want to parse.
    Since Prolog operators cannot model mixfix syntax,

    at least SWI-Prolog and SICStus Prolog fail,
    and I guess other Prolog systems fail as well.

    Mild Shock schrieb:
    Concerning the input (xxx yyy zzz) the OP wrote:

    I would expect it to print zzz(xxx(yyy)).

    Where did he get this requirement from, he didn’t
    compare other Prolog systems, right? So it came from
    his applicationdomain. But what was his application

    domain? Ok, lets proceed to an example with multiple
    brakets. Lets make the Pascal “begin” “end” example,
    by replacing xxx and zzz by “begin” and “end”.

    I get this result:

    ?- member(X,[begin,end]), current_op(Y,Z,X).
    X = (begin), Y = 1100, Z = fy ;
    X = (end), Y = 1100, Z = yf.

    ?- X = (begin
    |          x = 1;
    |          y = 2;
    |          begin
    |               z = 3
    |          end
    |       end).
    X = (begin x=1;y=2;begin z=3 end end).

    But is the abstract parse term, the Prolog result useful?



    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mild Shock@21:1/5 to Mild Shock on Thu Nov 14 05:24:49 2024
    So how will the computer science Professor help
    himself, and nevertheless show some compiler
    construction.

    If he lowers the expectation, he will use the curly
    braces, namely { .. }. This and the singleton list
    are practically the only braket syntaxes available

    in standard Prolog, that leave a term footprint. The
    normal parenthesis don’t leave any abstract parse tree.
    So this brave computer science Professor could go on:

    ompile({X}) --> compile(X). %%% scoping omitted
    compile((X;Y)) --> compile(X), compile(Y).
    compile((V=E)) --> [load(E),store(V)].

    And he would then succeed in demonstrating a toy compiler:

    ?- X = {
    x = 1;
    {
    y = 2
    }
    }, compile(X, L, []).
    L = [load(1), store(x), load(2), store(y)].

    But this is very poor. It doesn’t allow for DSLs that
    use different braketing syntax. And the computer science
    professor will switch to Isabelle/HOL, since switching

    to Prolog DCG is too painful?

    Mild Shock schrieb:

    Lets cut through the thicket. There is no
    real world use case of a (fy 1 yf). Take again
    the Pascal “begin” “end” mixfix example.
    Typically we want to then go on and write

    for example a compiler:

    :- op(1100,fy,begin).
    :- op(1100,yf,end).

    compile((begin X end)) --> compile(X). %%% scoping omitted
    compile((X;Y)) --> compile(X), compile(Y).
    compile((V=E)) --> [load(E),store(V)].

    The problem is the pattern (begin X end) will
    not work, if multiple (begin … end) are involved
    in the compile/1 call. You can try yourself, no

    Prolog system can do it:

    /* SWI-Prolog */
    ?- X = (begin
              x = 1;
              begin
                   y = 2
              end
           end), compile(X, L, []).
    false.
    %%% expected L = [load(1),store(x),load(2),store(y)]

    /* SICStus Prolog */
    ?- X = (begin
              x = 1;
              begin
                   y = 2
              end
           end), compile(X, L, []).
    no.
    %%% expected L = [load(1),store(x),load(2),store(y)]

    The reason is that the parser will join multiple yf,
    similarly it would join multiple fy. The parser will
    not follow a braket pattern. At least I don’t know
    any Prolog system that can do it.

    Mild Shock schrieb:
    Here is the SWI-Prolog and the SICStus
    Prolog abstract parse term. This is the real
    nightmare of every computer science professor,

    who wants to use Prolog in a compiler
    construction course:

    /* SWI-Prolog 9.3.14 */
    end(end(begin(;(=(x,1),;(=(y,2),begin(=(z,3)))))))

    /* SICStus Prolog 4.9.0 */
    begin(;(=(x,1),;(=(y,2),begin(end(end(=(z,3)))))))

    On the other hand mostlikely the OP @horsh
    would expect:

    /* What the End-User wants */
    end(begin(;(=(x,1),;(=(y,2),end(begin(=(z,3)))))))

    I think its impossible to do in any Prolog system,
    you would need a programming language with the
    possibility to do mixfix syntax definitions,

    like for example in Isabelle/HOL:

    (* Define the mixfix syntax for a Pascal-like block *)
    syntax
       "_begin_end" :: "'a ⇒ 'a" ("begin _ end")

    Or otherwise use DCG to write your own parser
    for the DSL at hand, that you want to parse.
    Since Prolog operators cannot model mixfix syntax,

    at least SWI-Prolog and SICStus Prolog fail,
    and I guess other Prolog systems fail as well.

    Mild Shock schrieb:
    Concerning the input (xxx yyy zzz) the OP wrote:

    I would expect it to print zzz(xxx(yyy)).

    Where did he get this requirement from, he didn’t
    compare other Prolog systems, right? So it came from
    his applicationdomain. But what was his application

    domain? Ok, lets proceed to an example with multiple
    brakets. Lets make the Pascal “begin” “end” example,
    by replacing xxx and zzz by “begin” and “end”.

    I get this result:

    ?- member(X,[begin,end]), current_op(Y,Z,X).
    X = (begin), Y = 1100, Z = fy ;
    X = (end), Y = 1100, Z = yf.

    ?- X = (begin
    |          x = 1;
    |          y = 2;
    |          begin
    |               z = 3
    |          end
    |       end).
    X = (begin x=1;y=2;begin z=3 end end).

    But is the abstract parse term, the Prolog result useful?




    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mild Shock@21:1/5 to Julio Di Egidio on Thu Nov 14 21:58:02 2024
    Yes, maybe, it depends. You would
    need to fill in some logic for the
    block functionality, like opening

    and closing a table with variable
    names. And try it as such with a larger
    variety of example. Also compare whether

    it works for both SWI-Prolog and SICStus
    Prolog. What one can already see for sure,
    the compile is not extremly safe anymore.

    It would also accept non well formed
    input. Like you can call it with unbalanced
    begin end now, and the compile/1 clause

    pattern matching will not fail, and it
    will start producing some code:

    ?- compile((begin x=1 end end)).

    But maybe this is a minor problem. Another
    challenge is for example the Pascal if-then-else.
    Basically a mixfix with 3 holes.

    if _ then _ else _

    https://www.tutorialspoint.com/pascal/pascal_if_then_else_statement.htm

    Just like in the begin end case, where
    we can provide non-well formed input
    like (begin x=1 end end). Ordinary

    Prolog operators will again not provide
    the safety and versatility for writing rules.

    Julio Di Egidio schrieb:
    This seems to do the trick:

    ```
    % SWI-Prolog 9.2.7

    :- op(1100, fy, begin).
    :- op(1100, yf, end).

    compile((begin XEnd)) --> compile(XEnd).
    compile((X end)) --> compile(X).
    compile((X;Y)) --> compile(X), compile(Y).
    compile((V=E)) --> [load(E),store(V)].

    compile_t(X, L) :-
        X = (
            begin
                x = 1;
                begin
                    y = 2
                end
            end
        ),
        compile(X, L, []).
    ```

    ```
    ?- compile_t(X, L).
    X = (begin x=1;begin y=2 end end),
    L = [load(1),store(x),load(2),store(y)].
    ```

    -Julio


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Julio Di Egidio@21:1/5 to Mild Shock on Thu Nov 14 21:21:50 2024
    On 14/11/2024 05:14, Mild Shock wrote:

    Typically we want to then go on and write
    for example a compiler:

    :- op(1100,fy,begin).
    :- op(1100,yf,end).

    compile((begin X end)) --> compile(X). %%% scoping omitted
    compile((X;Y)) --> compile(X), compile(Y).
    compile((V=E)) --> [load(E),store(V)].

    The problem is the pattern (begin X end) will
    not work, if multiple (begin … end) are involved
    in the compile/1 call. You can try yourself, no
    Prolog system can do it:

    /* SWI-Prolog */
    ?- X = (begin
              x = 1;
              begin
                   y = 2
              end
           end), compile(X, L, []).
    false.
    %%% expected L = [load(1),store(x),load(2),store(y)]
    <snip>

    This seems to do the trick:

    ```
    % SWI-Prolog 9.2.7

    :- op(1100, fy, begin).
    :- op(1100, yf, end).

    compile((begin XEnd)) --> compile(XEnd).
    compile((X end)) --> compile(X).
    compile((X;Y)) --> compile(X), compile(Y).
    compile((V=E)) --> [load(E),store(V)].

    compile_t(X, L) :-
    X = (
    begin
    x = 1;
    begin
    y = 2
    end
    end
    ),
    compile(X, L, []).
    ```

    ```
    ?- compile_t(X, L).
    X = (begin x=1;begin y=2 end end),
    L = [load(1),store(x),load(2),store(y)].
    ```

    -Julio

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mild Shock@21:1/5 to Mild Shock on Thu Nov 14 22:10:29 2024
    This is also a rather frustrating case,
    you might run into the same problem when

    you would try doing if-then-else:

    ?- X = (begin x=1 end; y=2; begin z=3 end).
    ERROR: Syntax error: Operator priority clash

    Unparsable in both SWI-Prolog and SICStus
    Prolog. On the other hand using {}/1 works:

    ?- X = ({x=1}; y=2; {z=3}).
    X = ({x=1};y=2;{z=3}).

    Mild Shock schrieb:
    Yes, maybe, it depends. You would
    need to fill in some logic for the
    block functionality, like opening

    and closing a table with variable
    names. And try it as such with a larger
    variety of example. Also compare whether

    it works for both SWI-Prolog and SICStus
    Prolog. What one can already see for sure,
    the compile is not extremly safe anymore.

    It would also accept non well formed
    input. Like you can call it with unbalanced
    begin end now, and the compile/1 clause

    pattern matching will not fail, and it
    will start producing some code:

    ?- compile((begin x=1 end end)).

    But maybe this is a minor problem. Another
    challenge is for example the Pascal if-then-else.
    Basically a mixfix with 3 holes.

       if _ then _ else _

    https://www.tutorialspoint.com/pascal/pascal_if_then_else_statement.htm

    Just like in the begin end case, where
    we can provide non-well formed input
    like (begin x=1 end end). Ordinary

    Prolog operators will again not provide
    the safety and versatility for writing rules.

    Julio Di Egidio schrieb:
    This seems to do the trick:

    ```
    % SWI-Prolog 9.2.7

    :- op(1100, fy, begin).
    :- op(1100, yf, end).

    compile((begin XEnd)) --> compile(XEnd).
    compile((X end)) --> compile(X).
    compile((X;Y)) --> compile(X), compile(Y).
    compile((V=E)) --> [load(E),store(V)].

    compile_t(X, L) :-
         X = (
             begin
                 x = 1;
                 begin
                     y = 2
                 end
             end
         ),
         compile(X, L, []).
    ```

    ```
    ?- compile_t(X, L).
    X = (begin x=1;begin y=2 end end),
    L = [load(1),store(x),load(2),store(y)].
    ```

    -Julio



    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Julio Di Egidio@21:1/5 to Mild Shock on Fri Nov 15 15:42:05 2024
    On 14/11/2024 21:58, Mild Shock wrote:

    Yes, maybe, it depends. You would
    need to fill in some logic for the
    block functionality, like opening

    Yes, the problem is a conflict in block scoping syntax, but it is only a problem with a shallow embedding *and* expecting to stay 100% faithful
    to the object language syntax.

    -Julio

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)