How to convert a string read from input to a list of lists in prolog

人盡茶涼 提交于 2019-12-25 06:52:06

问题


I'm trying to write a program that converts from Mayan to Arabic numerals and vice versa in prolog. Although I'm still running into some trouble I've managed to get it mostly working. I'm just wondering how if I read for example:

....| 0 .| |||

from a user input, how can I convert it to a list like this:

L = [ ['.','.','.','.','|'], [0], ['.','|'], ['|','|','|'] ]

I have an algorithm written getting from L to the arabic value, but I have no clue how to convert that string into a list.


回答1:


Take a look at this answer. The code I've written there splits a Prolog string on spaces to generate a list of atoms. With a small modification, you can alter the code to create strings instead of atoms. Here is the relevant code from the previous post, with the necessary modification for your case:

data([A|As]) --> 
    spaces(_), 
    chars([X|Xs]), 
    {string_to_list(A, [X|Xs])},  %% Using string_to_list/2 instead
    spaces(_), 
    data(As).
data([]) --> [].

chars([X|Xs]) --> char(X), !, chars(Xs).
chars([]) --> [].

spaces([X|Xs]) --> space(X), !, spaces(Xs).
spaces([]) --> [].

space(X) --> [X], {code_type(X, space)}. 
char(X) --> [X], {\+ code_type(X, space)}.

In your example, you'd take a Prolog string containing your example like "....| 0 .| |||" and run the above code using the built-in phrase/2, like so:

?- phrase(data(NumeralList), "....| 0 .| |||").
NumeralList = ["....|", "0", ".|", "|||"]

Note that I've tested this on SWI-Prolog and it works, but if you're using a different Prolog implementation, it mightn't support DCGs or the built-ins I've used.

If you were after a result which is precisely like what you've described as L above, you can modify the code further to return the list [X|Xs] directly in the data clause (removing the sub-goal {string_to_list(A, [X|Xs])},), and change the last predicate char to the following:

char(C) --> [X], {\+ code_type(X, space), atom_codes(C,[X])}.

Running this gives:

?- phrase(data(L), "....| 0 .| |||").
L = [['.', '.', '.', '.', '|'], ['0'], ['.', '|'], ['|', '|', '|']]

EDIT: As requested, here is the modified code which generates the above result in full:

data([[X|Xs]|As]) --> 
    spaces(_), 
    chars([X|Xs]), 
    spaces(_), 
    data(As).
data([]) --> [].

chars([X|Xs]) --> char(X), !, chars(Xs).
chars([]) --> [].

spaces([X|Xs]) --> space(X), !, spaces(Xs).
spaces([]) --> [].

space(X) --> [X], {code_type(X, space)}. 
char(C) --> [X], {\+ code_type(X, space), atom_codes(C,[X])}.



回答2:


In SWI-Prolog there is a builtin that almost gives what you need:

?- atom_chars('....| 0 .| |||', L).
L = ['.', '.', '.', '.', '|', ' ', '0', ' ', '.'|...].

Splitting on spaces can be done with another builtin, used in 'reverse' mode:

?- atomic_list_concat(L, ' ', '....| 0 .| |||').
L = ['....|', '0', '.|', '|||'].

Then we can combine these using maplist:

?- atomic_list_concat(L, ' ', '....| 0 .| |||'), maplist(atom_chars,L,G).
L = ['....|', '0', '.|', '|||'],
G = [['.', '.', '.', '.', '|'], ['0'], ['.', '|'], ['|', '|', '|']].

G it's very similar to what you need, just handle the '0'...



来源:https://stackoverflow.com/questions/9611134/how-to-convert-a-string-read-from-input-to-a-list-of-lists-in-prolog

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!