Logic programming library development log

Ah, okay.

My life has been too hectic lately for me to have a solid chunk of time to look at the library, but I'll get there...

No problem as far as I’m concerned. One’s personal life, and health, should always be one’s top priorities.

Getting back to logic programming and SICP section 4.4 ... since, as I have understood, Snap! 's list and Scheme's pair are somewhat different, how would:

(cons variable value)

(par. 4.4.4.8)

... translate to Snap! ?

  1. Logic programming SICP script pic, or
  2. Logic programming SICP script pic (1), or even
  3. Logic programming SICP script pic (2)|405x42, 5=100%

i think I have found the solution myself: it’s up to me to decide - as long as I’m consistently adhering to the same structure.

Yeah, you can do it however you want. But you're a little constrained by the fact that IN FRONT OF will only accept a list as its second input, whereas cons lets you put anything in the cdr. So for example a point on the plane which would naturally be (cons xposition yposition) in Lisp would have to be (LIST ...) in Snap!. If the list is stored as a Lisp-style linked list, that'd be two pairs rather than just one.

Would this be the Snap! translation of LISP / Scheme’s cons function?

No, because that's not invertible. It has to be that
(car (cons a b)) = a
(cdr (cons a b)) = b
and that doesn't work for cdr, because if you see (list a (list b)) you don't know whether its cdr is supposed to be b or (list b).

I've actually been wondering if there's a way to create imperfect lists, I.E. '(1 . 2).

No. That was a decision made in Scratch long ago, which we haven't, so far anyway, seen fit to change. I think that if we were ever to introduce pair mutation (SET ALL BUT FIRST OF _ TO _) (note the imperfect tense!), we might consider non-list pairs at the same time. Neither is very likely.

OK. Then I guess the only feasible general translation of a LISP / Scheme pair is a Snap! list of two items, while LISP / Scheme's list would translate to building nested 2-item lists in Snap!, much like the structure of streams. Is that right?

Yes, exactly.

I have a few questions about procedures on SICP section 4.4.4.2., paragraph "filters":

(define (lisp-value call frame-stream)
_ (stream-flatmap
_ _ (lambda (frame)
_ _ _ (if (execute
_ _ _ _ _ (instantiate
_ _ _ _ _ call
_ _ _ _ _ frame
_ _ _ _ _ (lambda (v f)
_ _ _ _ _ _ (error "Unknown pat var: LISP-VALUE" v))))
_ _ _ _ (singleton-stream frame)
_ _ _ _ the-empty-stream))
_ _ frame-stream))

  • What does call stand for? (is it a predicate?)
  • I was also puzzled by lambda (v f), but I think I know what it stands for now: the lambda function is an unbound variable handler that will ignore its second input - please correct me if I'm wrong.

(define (execute exp)
_ (apply (eval (predicate exp) user-initial-environment)
_ _ _ _ _ (args exp)))

  • Is apply equivalent to reportcall in Snap! ?
  • what is eval equivalent to in Snap! ?
  • what is the user-initial-environment?
  • where does (args exp) come in?

Another question, about sect. 4.4.4.7: what would symbol? translate to in Snap! ?

Sort of. The example just before Exercise 4.56 is

(and (salary ?person ?amount)
     (lisp-value > ?amount 30000))

so call is the list (< ?amount 30000).

Execute EVALs the < in user-initial-environment but doesn't eval anything else; it just does

(apply (eval ...) (args exp))

where the call to eval turns the symbol < into the less-than primitive predicate.

We're not quite done talking about execute, but these questions come first.

Apply is


so it's a variant of call that takes an input list instead of a variadic input. (Actually for real Lispians, it's apply that's fundamental and call (more typically called invoke) that's the variant. Eval and apply are objects of religious fervor to Lispians, because they do pretty much all the work of a Lisp interpreter. When we say things like "Inside every bad language interpreter there's a Lisp interpreter trying to get out" we mean that those other interpreters always have a version of eval (not necessarily called that, of course) and a version of apply (ditto), buried in syntax.)

We don't exactly have eval in Snap!, because code wasn't first class until just recently. It's sort of


where expression is Any(unevaluated) and environment is an environment, derived from
untitled script pic (3)
or one of its variants, most likely CALLER. I think what I wrote might even work, but I wouldn't swear to it. Anyway, it takes an expression and evaluates it, using the given environment to find values of variables. (Note: A Lisp environment, which is what we're talking about here, is different from a query language environment. The relevant environment here is user-initial-environment, which for our purposes means the global environment, but some Lisp interpreters, including the Chapter 4 one apparently, have an environment frame just for globals defined by the user, whose parent is an environment frame with the globals that come predefined when you fire up the interpreter (which, in the case of Scheme, includes all the primitive procedures, whose names are bound to them as ordinary variables).)

As for symbol?, Snap! doesn't distinguish text strings from symbols; any text string that isn't a number can be a symbol, which basically means "the name of a variable." So the closest we come is
untitled script pic (4)

So when we see (lisp-value < ?salary 30000) in a query we end up calling (in Lisp) (< 12000 30000) (or whatever the person's salary is). By the time we're in the Lisp world, there are no query system variables left in the expression, thanks to instantiate, so the only thing we had to look up in the Lisp environment is <.

I hope that helps!

By the way, I hope I said this before, but you don't have to write an exact copy of the SICP query system. The real Prolog does better at catching infinite loops, for example, I think. Just, whatever you end up with has to be callable from Snap! code.

Thx a lot! And yes, I know you didn’t ask me to write a copy of the SICP version. However the best way, for me, to study an intricate example, is to rebuild at least crucial parts of it; and then develop my own (if possible: improved) version.

  • The SICP example appears to be very well thought-out in many respects. It’s definitely superior to my initial version regarding unification, Booleans, and streams.
  • SICP is very rigorous regarding abstraction, going a long way towards readable code (though this is hindered, for me at least, by the Scheme syntax, which is so much less readable than e.g. Snap!); I may deviate from some of this for better efficiency (instead of using functions to abstract from the underlying data structure, I may use appropriately named variables as item numbers).
  • The table-directed procedure selection - BTW as an exercise I redeveloped the table reporter in Snap!, may share it when it will be good enough for general use - is really educational, and probably handy for a large project, but perhaps a bit exaggerated for this one.

SICP is the bible of computer science. Everything they do is brilliant. "Very well thought out" indeed! :~)

Although, actually, to my taste, the tiny abstract data types where the two selectors are obviously just car and cdr make the code harder to read. I believe in data abstraction, but I think they overdo it a little. I know this is heretical.

The thing about Lisp syntax is that you're supposed to edit in Emacs or some other Lisp-aware editor, so things are automatically indented correctly. It's funny that you compare it to Snap!, since of course our syntax basically is Lisp syntax, but with expressions colorized. You just have to remember that the rounded ends of the reporter blocks are really parentheses:
untitled script pic (2)
:~)

I think the data-directed dispatch is really lightweight and elegant! It makes the actual dispatch code tiny. And you don't have to edit the existing code of the evaluator to add a new special form. That makes it harder to introduce new bugs into the old code by mis-editing.

I agree, a table library is a great idea, although having dictionaries eliminates some of the need for them. Here, for example, you could have a dictionary with entries like
untitled script pic (3)

P.S. I see that I wrote

somehow turning ">" into "<." Sigh. I guess I have an affinity for workers rather than bosses.

I’m not impressed, being an atheist (though non-practicing).

3 Hail Mary’s!

It’s quite easy to write hard-to-read code in Snap!, too.

You may be right. Just using the Snap! dictionary function.

You just have to remember that the rounded ends of the reporter blocks are really parentheses

Yeah. I mean I've been saying that for a while lol.

We don't exactly have eval in Snap*!* , because code wasn't first class until just recently

I mean you DO. It's called Snap!

The thing about Lisp syntax is that you're supposed to edit in Emacs or some other Lisp-aware editor, so things are automatically indented correctly.

That's what blocks are. A use for whitespace that demonstrates human readability and how it can be used in computation research. It's such a monumental paradigm shift because it changes everything.

I gave up on SICP a while ago. Not because it's a bad book, but because it's not written for snap, snap makes too many subtle changes that scheme can't account for because the scheme it was written for is nearly 30 years old and snap! is new.

QW23's been doing some great work teaching themselves examples and figuring out the foibles that I can't.

Because basically what I want to do is write software, but coding has always been arcane smug rubbish that takes great pride in excluding others. Snap! gave me a gateway that I can't use because every other programming brand in existence is arcane ritualistic text.

Now as I've said previously, I understand why snap! made the decisions it did and as it's primary a teaching language, I even agree with them.

But I still want to write my own software and I want to do it in a block based ide, because there's no such thing as a block based ide. It's turtles text all the way down and always has been.

[scratchblocks] (Pick Random (1) to (10)) [/scratchblocks] is (Pick Random (1) to (10))

The only difference is that one has a markup signifier that the browser knows "When I receive [scratchblocks]" message and it's the same markup that knows to replace ":-)" with :slight_smile:

Which is why I try and try and try to figure out how to put a text parser in snap! and/or an ability to drop .c or .scm or .whatever files into snap, but the problem is, most existing software is writing in programming brands names that don't want you to solve the problem they want you to use their products without thinking too deeply about it.

That annoys the living duck out of me.

Ah, you should join my religion. We worship Alonzo Church, who invented computer science, at the same time Turing did. (In fact, Church was Turing's PhD thesis advisor, although that's a little misleading because Turing was already doing things before becoming an official grad student.) People just credit Turing with it because (1) he won World War II, and (2) nobody understood the importance of Church's lambda calculus until John McCarthy invented Lisp.

Oh, sure. But you can't blame that on the syntax we provide. You can write obfuscated code in any language!

The idea of SICP is that it isn't a book on how to program in Scheme; it's a book on how to program in any language. (That's especially true since finally, after 63 years, all those other languages have lambda!) Scheme just gets in the way less than most.

I get that you find it hard to learn the ideas without concrete programs to examine and to write. That's why John Denero at Berkeley rewrote it using Python (although he also changed a lot to emphasize OOP more), and why those other guys rewrote it using JavaScript, and why I want to rewrite it using Snap!. So, yeah.

Sorry, I deleted that because it was a leeetle antagonistic, I typed it quickly and went back to doing what I was doing lol.

get that you find it hard to learn the ideas without concrete programs to examine and to write. That's why John Denero at Berkeley rewrote it using Python (although he also changed a lot to emphasize OOP more), and why those other guys rewrote it using JavaScript, and why I want to rewrite it using Snap*!* . So, yeah.

Well no, I have the entire internet of concrete source to experiment with. The issue is I don't have a block based IDE to use any of it, because amongst other things, the unrelenting conspiracy abstraction is necessary.

Again. I need to state that I'm not opposed to snap and I understand why the safety features are there, but there NEEDS to be a third tier block language without those limitations. NEEDS., It's absolutely essential that something like that exists.

You can't "Leave it to the engineers" or "trust the computer knows what it's doing" anymore for as long as Scratch and Snap exist, because you're now teaching what used to be advanced university level knowledge to high-schoolers and acting surprised when they want to know more!

You're unlocking the key to the kingdom and then saying "No" (And the worst part is, it's not even intentionally)

You basically solved the problem. It's a writing idea but there's a thing for aspiring writers that you "Show not Tell" Which is you describe and explain the scene and the actions that happens instead of saying "Bob did this, Steve Did that and they all lived happily ever after"

Scratch And Snap! SHOW. Text Programming Brands are designed to tell, and only tell and not let you deviate from the path they choose, and the logical development of visual languages in advanced spaces is mind blowing... but no, we've still got to put up with Text Programming Brands refusing to vanish into the dusty archives of history

TL;DR;
Text is [scratchblocks] (Block (Is)) [/scratchblocks] TEXT.
Abstraction has to go.

I guess rewriting SICP is like eating an elephant: better do it one byte at a time. Like, Ch. 1 this year (though I think a Snap! manual update is more urgent for now - where the same adage may apply).

A major decision, I think, will be how to replace the SICP code with Snap! - is it going to be a literal translation? Or a rewrite from scratch - no pun intended - using the underlying ideas? IMO a serious dilemma with a literal translation would be whether to copy Scheme's pair type.

Would it help if someone wrote an automatic Scheme-to-Snap! translator? Or perhaps a set of Scheme blocks in Snap! ?

Sorry, I'm not much of a Church-goer: non-practicing, remember?

Huh. I just wrote a set of Scheme blocks in Snap!, including PAIRs.

Here you go.