Question

So basically I am trying to use some Prolog code to simulate pointer like behavior.

I asked a related question here, and after around one month, I finally have time to start.

Here is a simple example in C:

int a = 1;
int* p = &a;
int b = *p;   

And I want to translate this code into Prolog like this (or other better strategies?):

A is 1, 
assert(ref(p, a)),    <-  this can be dynamic fact gene
ref(p, TEMP),   <-  now I want to use a!!
to_lowercase(TEMP, TEMP1),  <- I don't know how to implement to_low
B is TEMP1.     <- reflection? 

So in the above code, I am confused with

  1. In my understanding, after ref(p, TEMP), then TEMP will equal to "a", and it is just a string, then how can I reuse it as a variable name, sounds like a reflection...?

  2. How to implement the to_lowercase function?

Am I clear?

Was it helpful?

Solution

If you are really that determined to simulate a computer from within Prolog, you should take into account the answers to your previous questions before moving on. Either way, this answer makes a lot of assumptions about what your ultimate goal is. I am guessing that you are trying to simulate a machine, and write a simulator that takes source code written in a C-style language and executes it.

So let's say you have a very simple processor with flat memory space (some small embedded microcontrollers are like this). Your whole memory then would be just one chunk of 16-bit addresses, let's say 1000 of them:

functor(Memory, memory, 1000).

Taking your C code above, a compiler might come up with:

  • Pick an address Addr1 for a, which is an int, and write the value 1 at that address
  • Pick an address Addr2 for p, which is an int *, and write the value of the address of a at that address
  • Pick an address Addr3 for b, which is an int, and write to it the value which is at the memory to which the value in p is pointing to.

This could translate to machine code for the machine you are simulating (assuming the actual addresses have been already picked appropriately by the compiler):

arg(Addr1, Memory, 1),     % int a = 1;
arg(Addr2, Memory, Addr1), % int *p = &a;
arg(Addr2, Memory, Tmp1),  %% put the value at p in Tmp1; this is an address
arg(Tmp1, Memory, Tmp2),   %% read the value at the address Tmp1 into Tmp2
arg(Addr3, Memory, Tmp2).  % int b = *p;

So of course all addresses should be within your memory space. Some of the calls to arg/3 above are reads and some are writes; it should be clear which is which. Note that in this particular conjunction all three arguments to the term memory/1000 are still free variables. To modify the values at an address that has been already set you would need to copy it accordingly, freeing the address you need to reuse.

Please read carefully all the answers to your questions before pressing on.

OTHER TIPS

You need to read a good book on Prolog. I'd suggest The Art of Prolog.

Prolog doesn't have anything like pointers, or addresses or variables. It's got terms. An unbound term is variable because it's not yet bound. Once bound (unified), it ceases to be variable and it becomes that with which it unified. It cannot be assigned a new value — unless the unification is undone via backtracking and an alternative path taken. Hence the term unification.

Trying to map the concept of pointers and memory addresses onto prolog is somewhat akin to putting fish gills on a bicycle.

As far as implementing a predicate for converting a strong to lower-case, you should realize that Prolog doesn't really have strings: the Prolog string "ABC" is exactly identical to the list [65,66,67], a a list of integers representing ASCII/Unicode code points. It is what is called syntactic sugar. So...given that identity...

Something like

to_lower( [] , [] ).
to_lower( [C|Cs] , [L|Ls] ) :-
  char_code('A',A),
  char_code('Z',Z),
  C >= A ,
  C =< Z ,
  ! , 
  char_code(a,Base),
  Offset = C - A ,
  L is Base+Offset,
  to_lower(Cs,Ls).
to_lower([C|Cs],[C|Ls]) :-
  to_lower(Cs,Ls).

Should do you.

Since you tag the question SWI-Prolog, I assume you have clear that the string concept has undergone some important change in recent times, mainly for efficiency reasons.

Look at downcase_atom/2, or string_lower/2, depending on your intended usage (I linked to string processing page, because the string_lower one has a typo).

For storing 'pointers' like objects, I suggest to use global variables, nb_setval/2, nb_getval/2, nb_current/2 instead of assert/retract. For first, are much more efficient (I measured time ago a factor of 3 in favour of nb_ predicate family), and make clearer the intended usage. assert/retract are better used to update a dynamic knowledge base.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top