 So we're going to start first by describing the entire language, and then after that we'll see if we have a minute or two left. It's going to be completely interactive as the other talks have been. There are just a small number of operators. So we're going to start with the easy ones. They're Simbolo. Simbolo. Simbolo. Absolutely. A little change of pace here, which basically says, if I ever get a value, I will be a symbol. And then we have another one called... Hold on! Sorry. Wait, wait, we can't do it this way. No, you need a run. I know. Well, we haven't... You haven't introduced one. Well, pretend like I have by showing it to them. This will get one value, and it will basically say, I don't know what I am, but I do know that I will be a symbol someday. So we can do the same thing for number O. You can sort of guess most of how that would work. And then we have another little one called NO-O. We have NO-O? We do have NO-O. Okay. Go ahead. And it will take a symbol, like, say, a closure. Whoa, it did that? It puts a five in there now? That's a nice touch. No food. So this sort of gives you an idea that you can keep a particular symbol from ever entering a data structure of any flavor. Now we do have simple control operators. I hope some of you are familiar with them. One is called FRESH, which introduces FRESH variables. And the last one is called KON-D, which allows you to have lots of answers, as you'll see very soon. We didn't introduce the most important operating length. No, we didn't. You want to? I think it's time. Yes. We also have unification, which allows us to give values to variables in various ways. And we have disunification, which allows us to say two things will never be the same. Do we have that? Okay. Hold on. Let me do the fresh. Okay. And there you are. So was it underscore zero? Did you say when underscore zero? Underscore says I don't know what I am ever going to be. Just it just hangs out there. Okay. So that's it. Wait, what? No? Hold on a second. You got more? Yeah. Okay. Hold on a second. Okay. All right. So you can unify X with five and now you get a five instead of underscore zero. Okay. Let's do a Kandee real quick. Real quick. One quick Kandee just for the fun of it. Okay. So syntactically Kandee looks like con in scheme. So let's do, okay. So if you say run one, that will say we'll get back at most one answer if it exists. And if you want, you can do a run two. Now in this case we have two answers. So in the first clause Q, which is our query variable is associated with X and Y. And in the second case it's associated with five. And if we want to get all the answers for sure, we can do a run star. And this gives us back a set of answers. And there are no more answers and it didn't go an innocent loop, which is nice. So that's a proof that those are all the answers there to be had because our search is complete and interleaving. So now what we're going to do is we're going to take a very, very simple program. And for some of you who have heard our talks, we use the pen. We're going to use something slightly different. We're going to use something called Rember from the Little Lisper that simply removes the first symbol that matches in a list. Very, very straightforward. And you can't ask for a much simpler recursive program. So Will is busy writing it there. If the list is empty, we'll return the empty list. If the car of the list is the thing we're looking for, we'll return the cutter of the list. And in the last case, we will simply write context to Rember X. Okay, so that should work. We all believe. And then we run it and let's find out. Perfect. And there we see that it removes it. So, simple enough. Now we want more answers than that. So we're going to rewrite it in mini-canon and let's see what happens. So the way that mini-canon works is you're just not allowed to make nested calls. So we're going to rewrite this entire thing without using any nested calls. So here we go. Whoa, hold on. Okay. Go ahead. First step. First step? Rename it. Okay? And somebody once asked me, what is that O in the end, right? That Rember O? So I thought, well, maybe this is a good place as any to tell you. It is the top of a question mark. It's just a piece of creativity. Okay. And question marks indicate predicates and predicates and relations have a lot to do with each other. And we're talking about relational programming. Second thing to do? Second thing, change the con to con d. No. No. Add an output variable, of course. So every function which took n arguments will now become a relation that takes n plus 1 arguments. Very simple. Very straightforward. Okay. Now we'll change the con to con d. And we will change the null to equal, equal the empty list to L. And well, now that we know we have the empty list, we have to give out some value. If we look at the right-hand side of the definition of Rember, it will be the value that's associated that we want to associate with out. And of course, out philosophically is like sort of the wrong name. Totally wrong. Yeah. Because no such thing as in and out variables on main camera. It's like, they're just variables. But it comes from a function. So thinking about it as an out at least for a very short time while you're writing it is not a bad idea. And then you have to forget that you did it. Okay. Now the next line is really simple. We introduced a couple of fresh variables for our car and cooter because we see we're going to use them. And now we say is actually you don't need the A. Let's get rid of that A. You're going with this? Okay. So now we're just going to find out what the list looks like. Well, it's got an X in it if we're successful. And it has a D in it because we might need it. And in fact we do. So what we're going to do is simply associate without that D and we've removed it. And that's all there is to D and A. I use as cars and critters. So helps you to know that. Okay. Now we come to the last line. And the very first thing we do is we throw out else. Goodbye else. Okay. So the next thing we have to do is we have to get our hands on the car and cooter. So we will do a fresh A, D. And then we will just do the obvious here, which is just do a call to Rembaro on the cooter. Yeah, of course that part. And then do a Rembaro D, Rez. We have to add an inner recursion value. And finally we will do the association of the original A with the result of the cooter. And we're done. Oh no, we basically did. It was move all the nest things. That's all we did. Oh yes, we do. Did call. I think. That would be X. Yes. Yes. Very good. Okay. So now we're done. We have implemented it and we've shown you how to write a recursive program. The whole language is now at your fingertips. That's it. Okay. So all we have to do now is try it out. So we want to know if we get the same answer and sure enough we do. So every program that ran that way before runs that way now except that there's an extra set of parentheses because we are anticipating wanting more answers. So let's see what happens if we do want more answers. Good enough. And there they are. What? We said we were going to remove B from the list. And there it is again. It's not a very, it's not a very good system. It has weaknesses. So Will, what can you do about that? Well, I think when we removed that else that could have been a problem. Okay. So don't just throw away the else. Okay. What else you got? Ah, now we use our Disquality Constraint. And lo and behold, A will never be the same as X. Yeah. So what does else mean in our original program? Else means that the tests in the previous clauses all fail. So this is the idea of a Dijkster guard if you're familiar with that. And we now have some technology called Dmatch. So you can write your scheme programs on the way to translating to mini-canron using Dijkster guard form so that you can reorder your con clause as any way you want. And this is something you might want to have in closure technology or some closure. It was a very simple macro. Yeah. I'm sure like David could do it. Steal it. Be my guest, you know. But it's nice when you're translating from closure to core logic to make sure that your clauses can be reordered anyway. And you have to make sure that you have tests that are making sure you don't end up on a clause when you should. Because in mini-canron, all the con D clauses are tried independently. Okay. So just because the first line match doesn't mean the second one won't be tried also. So we have to make sure that the second and the third clauses here don't overlap. Okay. So let's see what happens now. Oh, did I? Oh, yeah. Silly you, Max. Okay. You'd think by now it could read our minds. Really. And it could if we wrote it courage-style. It would work. It would work. Okay. So now we only have the one answer. We don't have any bogus information floating around. Okay. So we can now move on to... Dude, we want to try to push the room. Nah. This is more than enough. Okay. Okay. So at this stage, what we want to do... Oh, we didn't even show up wearing backwards though. Oh, we must run it backwards. Yes, of course. Don't forget. Okay. All right. I'll actually like fix this program. It has a subtle bug in it. Yes. A bug that makes you take forever. So when you run things backwards, you must use Wilbur's law, which is all recursions have to sync to the bottom of your code. Okay. So anytime you have a fresh with some recursions in it, move the recursions down. No harm because the ordering doesn't really matter, except it does. Okay. What did you do? Did you run it again? Are you ready? Ah, wait a minute. What is that? B-A-B-C. Oh, that must have been what you started with in order to get A-B-C back. And then you have A-B-B-C. Yeah, that's actually right. And it works. Because it's trying to put the B's anywhere before the first... So maybe you should run it with... Oh, you did run up in star. So those are all the answers. Yeah. I didn't mention that. Star means all the answers. Okay. So you have to be careful when you use it. Because all the answers can easily be infinitely long. Shall we show them? If you wish. Okay. There's ten answers. Those are ten very abstract answers. We have variables everywhere we can. And then we can get all the answers. And I'm going to quit that before my computer goes bad. Okay. I'm going to make a little shift now. And we're going to look at a scheme. Not many Cameron, but scheme interpreter. And it's going to be a very quick look. All right. You get to see it? Almost. Okay. But it's a vanilla scheme interpreter doing scheme. Okay. Except there's one little operator up there called fix. It's not the best thing to have self-application get generated later on when we worry about those such things. So there's nothing terribly, hopefully, confusing about this code. Oh, I have one over here, don't I? And I'm not going to explain it. It's rampant and it's a standard definition, so we can move on. We'll do a run-out or anything? Sure, a run-out. Okay. Let's demonstrate that it does factorial or something like that. You know that it does factorial. It really does work. So if you see the answer, 120, that's a really good sign. That's like a mini Cameron program you have to fill in the data. Okay. The empty environment and the factorial five program. There we are. 120. Okay. All right. So obviously that's not the exciting part. What we want to do instead is, what are you going to do? I don't know. I don't either. Okay. That's just something simple in the regular inferencer. So we're now going to show you the inferencer. And for those of you who have seen the St. Louis talk, we had a little fun with an inferencer. And unfortunately, we had a little fun with it yesterday too. And this morning, something seems to be a miss here. So we're going to have to forego using the fix in here. But fear not, we have plenty of interesting things to show you in any bend. Well, to set it up correctly. So Dan and I had this great idea for this cool new mini Cameron technology we were going to show off today. We're still going to show it to you. But it was a bug finding technology. And it worked so well that it found a bug in our inferencer that we were using to help show the bug. So yes, we actually use this to find the bug, but we haven't fixed the bug yet. It's going to be very simple. In fact, if you want to leave it up on one screen, then you can have the benefits of debugging on this side while we're showing the rest of the fuzzer technology. Oh, excuse me, sorry. All right, so what we want to do now is... Well, do you want to show it running? Yeah, we want to show it running. Let's do some type inferencing. Just make sure you commented out the fixed lines, please. So of all things, our fix needs a fix. It's broken. Okay. So, what do you want to type check down? Oh, I don't know. How about lambda x, lambda y times x, y? Lambda x. Lambda y times... Oh, you want... Okay, you don't want an application? No, we don't need an application. And then... Times x, y? Yeah, times x, y. And now we'll do that in the empty environment, which is... We're using the same order that we used in the interpreter, so it's an expression and an environment. But here, of course, we want to get back a type. So let's give ourselves a type. Oh, you've already produced the type, okay? Yeah. The type, it's a function that takes an integer and returns a function, and it also expects an integer and so on. But we could do something slightly better. We could... Oh, yeah. Do you want to go ahead? Just make something up. Let's just take that type we generated. Yeah. And pop that in. Sure. Yeah. Generate a program with that type. And there is the program. Now notice, by the way, there is a program there, but there's also some deals that had to get made to make this work. So we had to agree that certain things were going to be like symbols, certain things were going to be numbers, certain things were not going to be the symbol lambda and stuff like that. And from there, we can produce one answer. But are there more programs, perhaps, that have that type? Let's find out. What did we do? Did we start there? I was going to do, like, 10,000. Oh, what 10,000 wouldn't... How about 1,000? 1,000, maybe. One Mississippi. Oh, that was fast. Okay, so here comes our 1,000 programs that have the type arrow. No, no, it has, like, a couple of arrows in it. Right? It has, like, an arrow in. Yeah. Okay, so our type inference server, for the most part, works. You don't have to worry about it anymore, because we've taken a fix out of it. Okay, so now what we want to do is use this list of correct programs and hand it to the interpreter that we wrote in the scheme. All right, so here's what we're... Here's the basic idea. If you write a type inferencer in mini-canron, which we've done many times, but also on one of the production languages I'm working on for research, a GPU programming language, a functional GPU programming language that we want to embed in closure eventually, we have a type inferencer written in constraint mini-canron, which has mini-canron with a bunch of constraints in it. The cool thing is if you write your type inferencer in a very pure style, then you can run backwards, right? Okay, so this expression here will generate 100 well-typed terms in your language. So these have a correct grammatical structure and they type. Okay, so once you have that, then you can use that as a fuzzer. So you can take your well-typed terms and you can run it through your system to try to find bugs, or if it turns out that your system is actually correct but your type inferencer is wrong, you'll find errors that way too, which is what happened with us. Fun. Can you do it? Although this works well in theory, one of the problems is that mini-canron tends to be very lazy when trying to generate terms. So you say, hey, give me one program that's well-typed and I'll say, okay, a number. A number is a well-typed program. That's good. But then you say, okay, give me a second one and I'll say, okay, hash t. Hash t is a good program that's well-typed, right? So it doesn't really exercise all the corner cases of your system, okay? So we thought it'd be really cool if we could sort of amp up our fuzzer a little bit. So last night, we decided to implement. Canp. P stands for probability. Even though we're not actually using probabilities, we just request that you give numbers. P stands for probably works. Probably works. Don't forget, when you do this, you need to remove the fixed line. Oh, yeah, yeah, yeah. Well, we want to show off the canp. Oh, okay. Yeah, give it in. Go ahead, talk about it. Canp is, you can see the whole piece of code right there. It's beautiful. It's not bad. I have my things in syntax case. We won't get into that. But it's easy to rewrite this without the syntax case. And there's a little helper here called prefix sum, which basically says I've got a list of values and I will add them and keep track of where the accumulator that I'm adding them to goes and produce a list where the numbers just get bigger and bigger. And then it's finite, of course. So everything's fine. And it's a very small little program. I mean, we're talking really small, like the entire system is under 40 lines of code. We probably should just call the code closure because that's where we are, and it'd be much easier to remember. But anyway, so all we've done is change con e to have a number associated with it for each line of a con d. And that's it. And now we can run this program and presumably since there's a big giant number where the two is, we should get back a lot of twos and a very small number. God bless you. Another day. Keep going. And very few, a few... No. I guess nothing happens. Keep talking. So we're going to expect that there's a lot of twos in this thing. So let's see what happens. Wait a second. What? Help the people in the back. There you go. Okay. Oh, you're enlarging it. Yeah. That's a good idea. Okay. So con p, yeah. So now we can have this little example. So if we change these numbers to all ones, this means that you have the same probability of getting any of these answers back. One, two, or three, right? But if we want to make one of the answers more probable, then we can just kind of wait it. And if we want to put floating-point numbers or whatever... You can put any numbers you want in there. Yeah. So... As long as they work with addition. That's all. Okay. Yeah. So we can really skew it in one direction or another. So I guess we're not going to see too many threes. Yeah. Okay. So the cool thing for me about this program, the con p, was we actually didn't have to change any mini-candering code at all. Like we just could add code. So if you want to add your own notion... This is what we were trying to tell everyone, get the right definition of your language and then have it be flexible. You guys have all learned how to use inflexible languages at one point in your life, but you're not doing that anymore, are you? So that's what needs to happen. We need to be able to have the ability to just write the 40 lines and call it a day. Okay. Should we show off the interpreter? Should we have a working interpreter? Yes. I think we could show off the interpreter a little bit. Yeah. This is kind of the idea with the fuzzer here. So what we wanted is good answers, right? So we're going to... Do you have numbers on them? Yes. Yeah. So one problem... When you're trying to generate interesting answers with mini-candering and running an interpreter backwards, one of the classic problems is that it tries to generate these simple terms like hash-t or whatever, and you don't get too many procedure applications. Or the interesting types of terms in the Lambda Calculus. So we can weight heavily applications. So I put a 20 here and a one for Lambda terms, which are only values in this language, and then one for variables. And actually, I'll show you what it looks like when we put all ones first. Yeah, it's not very pretty. So if we just try to generate some programs here and their values... So let's do like 10 of them, I guess. Okay. So you'll see, because this is probabilistic, we can get the same answer back. We have overlap. But a lot of the terms are just Lambda. They're very boring. Some variable and some body, that's right. So if we want to skew it a little bit... We can put in... Yeah, yeah, yeah. We can put in a 20. And... Let's see if this works any better. Oops. Now it takes a little longer. But now you can see that our terms are much more complicated. So for example, that one has lots of applications in it. So our hope is by using this technology, you can easily create fuzzers. And if you want to create some gigantic terms, you know, without having to enumerate all of the smaller terms first, you can easily do that, run it through the rest of your system. So this is hopefully an example of how the purity is remaining pure. Like a lot of people will ask, well, with logic programming, that's great, but what does running backwards give you? Well, it gives you lots of flexibility. If you're going ahead and specifying the type system, you may as well use that to be able to generate terms of arbitrary complexity that are well-typed that you can then send through your system to stress them. And you'll also have the... Well, it's quine time. So let's learn a little bit about quines. Okay, so... You have to code up there yet? No. Okay. So the only difference between these two systems is we've added two new... two expression types. We got rid of the numbers. Yeah, yeah. Well, that'd be interesting. It might be, but not today. So... we have added two new expression types to our language. You're both... I'm sure you're familiar with both of them. One is called quote. And one is called list. And the only thing that's sort of interesting about quote is it says no quote closure in there because it turns out that you can generate expressions with the word quote. So if you... Because it doesn't know that you're going in or out. It doesn't have any idea what you're doing. The thing just works on its own. So the issue here is we have to have that no quote closure to just allow us to have some tag that we're in charge of. And that's the tag we've chosen. Okay, now... the others are just kind of obvious and certain, you know, not trivially obvious, but obvious given the time. Yeah. This not an embo is kind of neat because it allows you to have things like lambda, lambda, lambda as an expression in a language. The first lambda says I'm a lambda. The second lambda is just another name for a very nice variable. And the other one is that same variable. So you get the identity function, for example, if you do lambda, lambda, lambda. And you can play all sorts of crazy games like that. Now, how do we know this is necessary? Because it was generating a lot of gibberish. And we could deal... So we had to add this thing called not an embo that says I am not in the lexical scope at this point in time. Remember, when you're running things backwards, you get a little dizzy. Okay, it's quite tricky stuff. Okay, Will, do you want to add anything about this? Yeah, so when we demoed many canren last year at the unconference thing, the unconge thing, Stu Holloway, who may be here somewhere, asked... He is. Okay, he asked if our system, because we can run our interpreter backwards, just like we can run type register backwards, he wondered if we could generate quines. And a quine is a program that, when you evaluate it, evaluates to itself. And I thought that was a good problem. And so Dan, so I went off to the hotel room and pop, pop, pop. And I got a working version that night that kind of worked, but not really. And I showed it the next day. But then we spent basically the last year, so that's exactly... Yeah, yeah, I'm trying to follow a better version. And Eric Holk helped us a lot. And really, that problem was responsible for the addition of symbol O and number O. No O. And no O. That was a great problem. So let's move on to an example. Could we do that? Yeah. Okay. Oh, nice. Just remove it. Put it out or something. You know what a thrine is, by the way. It's up there. It says... No, I don't tell them. Well, okay. Come on. All right. Okay. Ready? Mm-hmm. Okay. So let's do... Okay. So the question is, we've got this eval-expo thing which takes an expression, an environment, an output answer, like that. Okay. And the question is, how can we use this program to generate a program that evaluates to itself? So what can I write here for X... Well, for environment, we want it to evaluate in the empty environment. So we don't care about... We don't want any variable bindings in place. But what expression can we have and what output can we have to make sure that we're going to generate any ideas? QQ. Okay. That sounds good. Okay. So we want the same expression as the input and the output. Okay. There it is. Believe it or not, there it is. I don't believe it, Dan. How can we find out? I don't know. Let's see. What if we evaluated that and saw if it was the same thing? Here is the program I just grabbed from that. I'm going to call it Q. I have to quote it prematurely. Okay. So this is our Q program. I know you don't, but I'm trying to... That's a little in-joke. I know. Dan doesn't like me using eval, but I'm going to do that. I don't even see what's on the blackboard. Okay. You evaluate this expression. What do we get back? Oh, that looks familiar. All right. Now let me prove it. Boom. That's a pretty good proof. Can you generate more than one? I don't know. Let's see. How about two? How about 12? 12? All right. Three. How about five? All right. Not too bad. Anyway, these are all legitimate quines. They couldn't possibly be anything else, in fact. Considering the shortness of that program, it's like almost frightening. Okay. What's a trine? How about a twine first? Oh, right. What's a twine? I bet by induction you could figure out how to do thrines or caudrines or quintines. Little induction, you'll be all set. What does a twine do? Oh, you have to ask me that again. I always get confused. A twine. Twines are when you have two programs, P and Q, where P and Q are different and how do we secue and Q evaluates to P? Do you think we can generate those? All right. Well, how would we do that? I would be... You left out part of the description. What? Well, that they're not the same. Oh, you did. I'm sorry. Okay. So, let's say your output is...our query variable is going to be R and we have P and Q as programs. So, how do we write this program? So... P evaluates to Q and then Q evaluates to P and since Will said they have to be different, let's make them different. Let's watch it run. Oh, I forgot. What happened? Slight fail. Hold on. Did you leave something out? No. Oh, whoops. Hold on. You want to make them laugh? Yeah, I forgot. You forgot Will Bird's Law. Oh, you didn't show anything. I forgot to actually like... You forgot to give a value for them. It actually generated a coin, but it wasn't going to show anything. It was a very interesting one. There it is. Okay, so we have two programs here. All right. Okay, so you got that expression and that expression. Okay. So, let's define Q, or no, P to be the first one. Okay, you have to quote it. Nope, nope, nope. The final thing that's it. That's it. I've done this before. All right. All right, let's P and then... I trust them. Q. Okay, all right. So, let's see here. We got P and we have Q. All right, let's see if this works. So, should be able to val P that should be equal N to Q. Right? Should we go for broke here? Okay. Sorry. I'm getting nerd chills. Okay. Oh, all right. There you go. I'm nervous. Okay, so you get the story and by induction you can play content and as always all of the code and the description and maybe the improvement in fix will be available on Will's GitHub and you can all play with it and have some fun with it. Yeah, the clients are on GitHub and we're also going to put up well, Khan P will also be there. And we'll fix that plug in the type that we found by buzzing. I don't believe the syntax case will survive. Yeah, maybe. That's it. Yes, that's it. And please make your programs be pure and run them backwards and be awesome.