[m-users.] higher order issue: `ground` seen but expecting higher-order pred
Sean Charles (emacstheviking)
objitsu at gmail.com
Thu Oct 6 03:13:40 AEDT 2022
I must be to stupid to get it, unusually, I am pasting the entire source file as it stands along with the error message, I just don't get it. I just don't today, apologies for the long post of source code. I've tried re-reading the relevant parts of the documentation but it's just not sinking in, the language is too technically dry and formal for my uneducated brain.
SOURCE CODE:
➜ fbnf cat -n fbnf.m
1 %-----------------------------------------------------------------------------%
2 %
3 % File: fbnf.m
4 % Main author: Sean Charles
5 % Date: Sat Oct 1 19:48:26 2022
6 %
7 % FORTH but not FORTH
8 %
9 %-----------------------------------------------------------------------------%
10 :- module fbnf.
11
12 :- interface.
13 :- import_module io.
14
15 :- pred main(io::di, io::uo) is det.
16
17
18 :- implementation.
19
20 :- import_module bool.
21 :- import_module list.
22 :- import_module map.
23 :- import_module maybe.
24 :- import_module stack.
25 :- import_module string.
26
27
28 %----------------------------------------------------------------------------%
29
30 main(!IO) :-
31 io.command_line_arguments(Args, !IO),
32 Arg = string.join_list(" ", Args),
33 io.format("ARG: %s\n", [s(Arg)], !IO),
34
35 ( if string.is_empty(Arg) then
36 repl(initial_state, _, !IO)
37 else
38 interpret(string.words(Arg), initial_state, State1, !IO),
39 repl(State1, _, !IO)
40 ).
41
42 %----------------------------------------------------------------------------%
43
44 :- type lstr == list(string).
45
46 % This is the WORD handler definition
47 %
48 %:- type word_handler == (pred(fstate, fstate, io, io, lstr, lstr)).
49 %:- inst word_handler == (pred(in, out, di, uo, in, out)is det).
50
51 :- type word_handler
52 ---> word_handler(
53 pred(
54 fstate::in, fstate::out,
55 io::di, io::uo,
56 lstr::in, lstr::out) is det
57 ).
58
59 :- type word_map == map(string, word_handler).
60 :- type stack_entry == stack(int).
61
62 %
63 % FBNF operating state
64 %
65 :- type fstate
66 ---> fstate(
67 fs_compiling :: bool,
68 fs_terminate :: bool,
69 fs_dict :: word_map,
70 fs_stack :: stack_entry,
71 fs_error :: maybe(string)
72 ).
73
74
75 % Create the initial state of the machine.
76 %
77 :- func initial_state = (fstate::out) is det.
78
79 initial_state =
80 fstate(
81 no, % interpret mode
82 no, % terminate requested ?
83 initial_dictionary, % core words
84 stack.init : stack_entry, % initial empty stack
85 no % no error message
86 ).
87
88
89 % Create default system WORDS dictionary.
90 % Here we pre-load all the stock words that the user can build on
91 % during the course of the session.
92 %
93 :- func initial_dictionary = (word_map::out) is det.
94
95 initial_dictionary = Map :-
96 some [!Words] (
97 !:Words = map.init,
98
99 map.set(":", word_handler(define_word), !Words),
100 map.set("bye", word_handler(session_end), !Words),
101 map.set("words", word_handler(list_words), !Words),
102
103 Map = !.Words
104 ).
105
106 %----------------------------------------------------------------------------%
107 %----------------------------------------------------------------------------%
108 %
109 % System WORD Implementations
110 %
111 %----------------------------------------------------------------------------%
112 %----------------------------------------------------------------------------%
113
114 % ":" - define a new word.
115 %
116 :- pred define_word(fstate::in, fstate::out, io::di, io::uo,
117 lstr::in, lstr::out) is det.
118
119 define_word(!State, !IO) -->
120 {
121 io.format("DEFINE WORD\n", [], !IO)
122 }.
123
124 % "BYE" - terminate the current session.
125 %
126 :- pred session_end(fstate::in, fstate::out, io::di, io::uo,
127 lstr::in, lstr::out) is det.
128
129 session_end(!State, !IO) -->
130 {
131 io.format("BYE\n", [], !IO)
132 }.
133 % "WORDS" - list all defined words.
134 %
135 :- pred list_words(fstate::in, fstate::out, io::di, io::uo,
136 lstr::in, lstr::out) is det.
137
138 list_words(!State, !IO) -->
139 {
140 io.format("WORDS\n", [], !IO)
141 }.
142
143 %----------------------------------------------------------------------------%
144
145 % Read-Eval-Print-Loop
146 %
147 :- pred repl(fstate::in, fstate::out, io::di, io::uo) is det.
148
149 repl(!State, !IO) :-
150 io.format("fbnf> ", [], !IO),
151 io.flush_output(!IO),
152 io.read_line_as_string(Res, !IO),
153 (
154 Res = ok(Str),
155 interpret(string.words(Str), !State, !IO),
156 repl(!State, !IO)
157 ;
158 Res = error(Err),
159 io.format("error: %s\n", [s(io.error_message(Err))], !IO),
160 repl(!State, !IO)
161 ;
162 Res = eof,
163 io.format("Bye!\n", [], !IO)
164 ).
165
166 %----------------------------------------------------------------------------%
167
168 % from "Starting FORTH" ...
169 %
170 % This will activate a word called INTERPRET, also known as the “text
171 % interpreter.” The text interpreter scans the input stream, looking for strings
172 % of characters separated by spaces. When a string is found, it is looked up in
173 % the dictionary.
174 %
175 % If the word is in the dictionary, it is pointed out to a word called EXECUTE.
176 % EXECUTE executes the definition (in this case an asterisk is printed).
177 % Finally, the interpreter says everything’s “ok.”
178
179 % 'INTERPRET'
180 % Process the current input stream of user tokens.
181 % If an error is detected then we abort the loop and abandon the input.
182 % Anything processed up to the error remains intact though this may or may
183 % not lead to a safe state (TBD).
184 %
185 :- pred interpret(list(string)::in, fstate::in, fstate::out,
186 io::di, io::uo) is det.
187
188 interpret(Words, !State, !IO) :-
189 compiling(no, !State),
190 interp1(Words, !State, !IO).
191
192
193 :- pred interp1(list(string)::in, fstate::in, fstate::out,
194 io::di, io::uo) is det.
195
196 interp1([], !_, !_).
197
198 interp1([W|Ws], !State, !IO) :-
199 io.format("interp1: %s\n", [s(W)], !IO),
200 execute(W, Ws, Rest, !State, !IO),
201 flush_error(HadError, !State, !IO),
202 ( if HadError = yes then
203 true % abandon ship.
204 else
205 interp1(Rest, !State, !IO)
206 ).
207
208 % 'EXECUTE'
209 % Find the word in the dictionary so we can invoke it, if it's not
210 % found we want to record the error and terminate processing.
211 %
212 :- pred execute(string::in, list(string)::in, list(string)::out,
213 fstate::in, fstate::out, io::di, io::uo) is det.
214
215 execute(Word, Words, Rest, !State, !IO) :-
216 Dict = fs_dict(!.State),
217 ( if map.search(Dict, Word, word_handler(Entry)) then
218 Entry(!State, !IO)
219 else
220 set_error(string.format("word not found: %s\n",
221 [s(Word)]), !State)
222 ),
223 Rest = Words.
224
225 %----------------------------------------------------------------------------%
226 %----------------------------------------------------------------------------%
227 %
228 % STATE change operations
229 %
230 %----------------------------------------------------------------------------%
231 %----------------------------------------------------------------------------%
232
233 % Set 'compiling' mode as indicated.
234 %
235 :- pred compiling(bool::in, fstate::in, fstate::out) is det.
236
237 compiling(Mode, !State) :-
238 !:State = !.State ^fs_compiling := Mode.
239
240 :- func is_compiling(fstate::in) = (bool::out) is det.
241
242 is_compiling(S) = S ^fs_compiling.
243
244
245 % Set an error message into the state.
246 %
247 :- pred set_error(string::in, fstate::in, fstate::out) is det.
248
249 set_error(Message, !State) :-
250 !:State = !.State ^fs_error := yes(Message).
251
252 % Flush (by writing) the current error message.
253 % Flushed will be 'yes' if there was an error in the state record
254 % and this will cause the current processing to abort.
255 %
256 :- pred flush_error(bool::out, fstate::in, fstate::out, io::di, io::uo) is det.
257
258 flush_error(Flushed, !State, !IO) :-
259 (if yes(Error) = !.State ^ fs_error then
260 io.format("error: %s\n", [s(Error)], !IO),
261 Flushed = yes
262 else
263 Flushed = no
264 ).
265
266 %----------------------------------------------------------------------------%
267 :- end_module fbnf.
268 %----------------------------------------------------------------------------%
ERROR OUTPUT:
➜ fbnf cat fbnf.err
fbnf.m:218: In clause for predicate `execute'/7:
fbnf.m:218: in argument 1 (i.e. the predicate term) of higher-order predicate
fbnf.m:218: call:
fbnf.m:218: type error: variable `Entry' has type
fbnf.m:218: `pred(
fbnf.m:218: fbnf.fstate :: builtin.in,
fbnf.m:218: fbnf.fstate :: builtin.out,
fbnf.m:218: io.state :: builtin.di,
fbnf.m:218: io.state :: builtin.uo,
fbnf.m:218: list.list(string) :: builtin.in,
fbnf.m:218: list.list(string) :: builtin.out
fbnf.m:218: ) is det',
fbnf.m:218: expected type was
fbnf.m:218: `pred(
fbnf.m:218: V_7,
fbnf.m:218: V_8,
fbnf.m:218: V_9,
fbnf.m:218: V_10
fbnf.m:218: )'.
fbnf.m:218: The partial type assignment was:
fbnf.m:218: Word_8: string
fbnf.m:218: Words_9: list.list(string)
fbnf.m:218: Rest_10: list.list(string)
fbnf.m:218: Dict_13: tree234.tree234(string, fbnf.word_handler)
fbnf.m:218: Entry_14: (pred((fbnf.fstate :: builtin.in), (fbnf.fstate ::
fbnf.m:218: builtin.out), (io.state :: builtin.di), (io.state ::
fbnf.m:218: builtin.uo), (list.list(string) :: builtin.in),
fbnf.m:218: (list.list(string) :: builtin.out)) is det)
fbnf.m:218: STATE_VARIABLE_State_0_15: fbnf.fstate
fbnf.m:218: STATE_VARIABLE_State_16: fbnf.fstate
fbnf.m:218: STATE_VARIABLE_IO_0_17: io.state
fbnf.m:218: STATE_VARIABLE_IO_18: io.state
fbnf.m:218: V_19: fbnf.word_handler
It's basically the same error I had last time via a different route as far as my limited brain can tell. Some days this higher-order stuff just makes no sense to me at all how Mercury does it.
Sorry.
> On 5 Oct 2022, at 08:59, Sean Charles (emacstheviking) <objitsu at gmail.com> wrote:
>
> Thanks Julien, I will try that.
>
> About the state vars/DCG... yes, I don't like it either and today I am going to remove the DCG style... I am such an old Prolog stalwart that sometimes I do it without realising it! :D And my brain isn't 100% yet; as I told Volker, I recently had 70% of my liver removed (cancer) and the resulting brain fog has been, shall we say, amusing to observe and very frustrating to live with, but it gets clearer ever day now.
>
> I do remember a post from Volker a long time ago on a very similar matter but try as I might I just couldn't find it for reference.
>
> Thanks again,
> Sean.
>
>
>> On 5 Oct 2022, at 04:25, Julien Fischer <jfischer at opturion.com> wrote:
>>
>>
>> Hi,
>>
>> On Tue, 4 Oct 2022, Sean Charles (emacstheviking) wrote:
>>
>>> I am fleshing out a VERY loose forth type system, I have the following definitions to allow me to set up a map of word names and there handlers:
>>> :- type lstr == list(string).
>>> :- type word_handler == (pred(fstate, fstate, io, io, lstr, lstr)).
>>> :- inst word_handler == (pred(in, out, di, uo, in, out)is det).
>>> :- type word_map == map(string, word_handler).
>>> :- type stack_entry == stack(int).
>>
>> As Volker mentioned, this won't work as the inst of nearly every output
>> argument in the map module is ground and the higher-order inst will be
>> lost.
>>
>> An alternative would be to use combined higher-order types and insts and
>> define the word_handler type as:
>>
>> :- type word_handler
>> ---> word_handler(pred(fstate::in, fstate::out, io::di, io::uo, lstr::in, lstr::out) is det).
>>
>> That should do what you want with fairly minimal changes elsewhere
>> (mainly accounting for the the word_handler wrapper that is now around
>> the higher-order term).
>>
>> ...
>>
>>> I am not sure the DCG style will remain but it's pure proof of concept / exploratory at the moment.
>>
>> IMO, mixing DCGs and state variables like that looks weird.
>>
>> Julien.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.mercurylang.org/archives/users/attachments/20221005/8d3871d1/attachment-0001.html>
More information about the users
mailing list