nuxi
Members-
Posts
87 -
Joined
-
Last visited
Recent Profile Visitors
608 profile views
nuxi's Achievements
Star Raider (3/9)
110
Reputation
-
I still want to get the accumulator out of the equation, but I might as well share REDUCE. I think if I do it recursively, I can maybe make it work. But cribbing off of your work was super helpful in the meantime . TO REDUCE :FUNC :LST :ACC MAKE "ANSW [ ] TELL :LST EACH [RUN ( SENTENCE [MAKE "AC C ] :FUNC [:ACC YN MAKE "ANSW LPUT :ACC :ANSW ] ) ] OUTPUT LAST :ANSW END ? REDUCE "SUM [1 2 3 4 ] 0 10 ? REDUCE "PRODUCT IOTA 7 1 5040
-
Well, nodes aren't cons cells. They don't seem to make any sense at all, to be honest. Will have to wait until I can do some analysis of the memory map, or some kind person who knows GPL helps detangle it. I'm still searching for a new, less ambitious project. In the meantime, here's a handy function salvaged from the first attempt: TO CARTESIAN :LIST1 :LIST2 IF :LIST1 = [ ] OUTPUT [ ] STOP MAKE "HEAD FIRST :LIST1 MAKE "TAIL BUTFIRST :LIST1 OUTPUT SENTENCE ( PAIR :HEAD :LIST2 ) ( CARTESIAN :TAIL :LIST2 ) END TO PAIR :ITEM :LIST IF :LIST = [ ] OUTPUT [ ] STOP MAKE "HEAD FIRST :LIST MAKE "TAIL BUTFIRST :LIST OUTPUT FPUT ( SENTENCE :ITEM :HEAD ) ( PAIR :ITEM :TAIL ) END ?PRINT CARTESIAN [2 3 4 5 6 7 8 9 10 J Q K A ] [S H D C ] [2 S ] [2 H ] [2 D ] [2 C ] [3 S ] [3 H ] [3 D ] [3 C ] [4 S ] [4 H ] [4 D ] [4 C ] [5 S ] [5 H ] [5 D ] [5 C ] [6 S ] [6 H ] [6 D ] [6 C ] [7 S ] [7 H ] [7 D ] [7 C ] [8 S ] [8 H ] [8 D ] [8 C ] [9 S ] [9 H ] [9 D ] [9 C ] [10 S ] [10 H ] [10 D ] [10 C ] [J S ] [J H ] [J D ] [J C ] [Q S ] [Q H ] [Q D ] [Q C ] [K S ] [K H ] [K D ] [K C ] [A S ] [A H ] [A D ] [A C ] These can be tighter, to save space, but leaving the originals for readability TO CARTESIAN :LIST1 :LIST2 IF :LIST1 = [ ] OUTPUT [ ] STOP OUTPUT SENTENCE ( PAIR F :LIST1 :LIST2 ) ( CARTESIAN BF :LIST1 :LIST2 ) END TO PAIR :ITEM :LIST IF :LIST = [ ] OUTPUT [ ] STOP OUTPUT FPUT ( SENTENCE :ITEM F :LIST ) ( PAIR :ITEM BF :LIST ) END
-
Yeah. I just thought I'd bury them one level lower, since it will be annoying to start a program with MAIN 0 0 0 0 0 0 . I wonder if nodes are just cons cells? That would make sense at least. I should be able to work that out empirically ... Speaking of memory usage. I rewrote VECTOR once I realized sentence, first and butfirst all have short forms. I HATE doing it, but it lets me fit everything on one line, and consequently saves a variable. TO VECTOR :FN :L1 :L2 IF NOT LENGTH :L1 = LENGTH :L2 OUTPUT "FALSE STOP MAKE "ANS [ ] REPEAT LENGTH :L1 [RUN ( SE [MAKE "ANS LPUT ] :FN [F :L1 F :L2 :ANS MAKE "L1 BF :L1 MAKE "L2 BF :L2 ] ) ] OUTPUT :ANS END
-
I own two of the CorComp version. Is there a compelling reason other than completionism that I might want to swap one out for one of these? I was under the impression there wasn't much of a difference.
-
OH OH OH. I think you've got it. That trick should let us safely handle long variables. If we can force local scope just by having variables as parameters somewhere higher up, we can do this: TO GAME: LOCAL_ENV 0 0 0 0 0 0 END TO LOCAL_ENV :FOO :BAR : BAZ :A1 :A2 :A3 SETUP MAIN_LOOP END And that should take care of the issue. Just need to make sure that: 1) any new (long) variables are added to the local_env call, and 2) during development you don't run any procedures directly, instead you put the call you want to test inside local_env and run from there. Not exactly an ideal development process, but it should work!
-
You look like you have pretty shallow profile keycaps. Will those fit on the front, or were you going to put them on top? I'm going to try and find some SA or OEM keycaps that I like and put decals on the front. That way I don't need to worry about wear and tear
-
I get it. These are fantastic to have, though, thanks! IOTA and MAP have a ton of potential uses. Here's VECTOR, an abstracted version of MULTV. I thought it would be polite to return something if the lengths don't match. Don't know if there's any convention, false, or [ ], so I just picked one. TO VECTOR :FUNC :LS1 :LS2 IF NOT LENGTH :LS1 = LENGTH :LS2 OUTPUT "FALSE MAKE "ANSW [ ] MAKE "LMDA ( SENTENCE [MAKE "ANSW LPUT ] :FUNC [FIRST :LS1 FIRST :LS2 :ANSW MAKE "LS1 BUTFIRST :LS1 MAKE "LS2 BUTFIRST :LS2 ] ) REPEAT LENGTH :LS1 [RUN :LMDA ] OUTPUT :ANSW END PRINT VECTOR "PRODUCT [2 3 4 ] [2 3 4 ] 4 9 16 PRINT VECTOR "SUM [2 3 4 ] [2 3 4 ] 2 6 8 Worth looking in to. One thing I've noticed is that anything you MAKE is always global scope. It would be great if we could put a bunch of ERASEs in to clean up temporary variables, but unfortunately, it takes an entire half-second to run. So I'll have to use them sparingly. But I still think it will be necessary in come cases.
-
To be fair, what jschultzpedersen and I were doing above was a pretty advanced topic, and consequently a bit cryptic. What Logo is good at, as a lisp dialect, is lists and recursion. Let me give you an example of what I was hoping to do with it, though it's increasingly looking like I'm going to need to go for something less ambitious. I was going to try and implement the game of Marrakesh: https://boardgamegeek.com/boardgame/685/marrakesh . It's a unique mishmash of card game and backgammon. The play is in rounds where you try and score tricks, which then let you bear off men as in backgammon. You have three chances to get all 6 of your men borne off, and you score based on whether you were successful, with bonuses for certain patterns. Obviously, the deck of cards is a list, along with the hands, and the cards in play. So is the results of the dice throws. As are the positions of each of the men, the patterns in which they were borne off, and the scorepad. The placement of all of the characters to make the board? Also a list. Where I can demonstrate some of the (potential, I'm going to cheat a bit and pretend everything worked without limitations) power is with scoring, which is also ... a list. Here's the scorecard: I'm going to start with a procedure straight from the book, LOOKUP, which has a helper function called ENTRY. LOOKUP allows us to implement a dictionary. TO ENTRY :KEY :TABLE IF :TABLE = [] OUTPUT [] IF :KEY = (FIRST FIRST :TABLE) OUTPUT (FIRST :TABLE) OUTPUT ENTRY :KEY (BUTFIRST :TABLE) END TO LOOKUP :KEY :TABLE MAKE "PAIR ENTRY :KEY :TABLE IF :PAIR = [] OUTPUT [] OUTPUT LAST :PAIR END Now we can implement the scorecard: TO MAKESCORECARD MAKE "OFF_VALS [[[2 2 2] [Casablanca 6]] [[3 1 2] [Rabat 6 ]][[1 1 4] [Bogart 9]] ... ] MAKE "DEF_VALS [[[1 1 1] [Little Fez 4]] [[1 1 0] [Common Fez 6]] ... ] END And now the scoring routine (this is from memory, it's part of what got destroyed last night): TO OFF_SCORE :PATTERN IF NOT LOOKUP :PATTERN :OFF_VALS = [ ] OUTPUT LOOKUP :PATTERN :OFF_VALS //if it's in the dictionary, return the value IF FIRST :PATTERN + FIRST BUTFIRST :PATTERN = 6 OUTPUT [Gammon 6] //sum the first two tricks IF FIRST :PATTERN + FIRST BUTFIRST :PATTERN + LAST :PATTERN = 6 OUTPUT [Game 3] //sum all three tricks OUTPUT [] END Same for the defensive scores, with some special handling in case of Backgammon not granting a defensive score to the other player, and how to count pips if no one bears all 6 off, etc. The display routine can then show the name of the scoring pattern, while the scoring routine peels off just the number. And what's beautiful is now any properly formatted list is now a dictionary, thanks to LOOKUP existing. No special types or declarations required. Just toss the list and a key at lookup, and it will tell you how they are associated. E.g., which dice characters are associated with which numbers, or which suit characters correspond to the suits: [[[S] [129]] [[C] [130]] [[H] [131]] [[D] [132]]] Lisps are neat! And I'm barely proficient at them.
-
One more refinement of MAP, allowing you to apply any function, not just those that take one argument (although division will be an issue and since we're all integers, just using the reciprocal won't help, but you can write a SWAP helper function). TO MAP :FUNC :LST MAKE "ANSW [ ] TELL :LST EACH [RUN ( SENTENCE [MAKE "ANSW LPUT ] :FUNC [YN :ANSW ] ) ] OUTPUT :ANSW END MAP [SUM 5 ] IOTA 3 6 7 8 And it will allow you to apply any function to the elements of a list. Unfortunately, not every procedure in Logo is a function. Turtle commands, for instance. But we can do something like this: TO SQUARE N: TELL TURTLE REPEAT 4 [FD :N RT 90 ] OUTPUT "TRUE END Except we don't actually want that output, so this will be handy: TO IGNORE FOO: END Which lets us do fun things like:
-
That's great! I'd love to see the article (and the prior one). I took a stab at reduce last night ( /, or probably OVER, if we're going with APL terminology), and I'm close, but I also have an accumulator parameter I want to get rid of. If you want to share your version of SUMUP and MULTV, we could work to abstract them into OVER and, I dunno, MATRIX. Does that mean 20% of nodes, or do you have some other way to measure memory consumption? I'm not looking forward to it, but I wonder if I'll also need to start diving into the memory map to see if we can get an idea of how much overhead we're dealing with for various things. Turns out (I could have figured this out if I'd have thought through things), you can't even represent a deck of cards without bumping into the list size limit. Very disappointing. So I will definitely have to write a cleanup routine. I will also probably have to scale back what I'm going to attempt (there's a reason I've been nebulous. Don't like announcing vaporware). It's frustrating because I'm discovering Logo II is at once incredibly powerful, and severely limited. Almost worse than it being entirely worthless.
-
Well, I broke it. Twice. Once on purpose and once by accident. As mentioned above, the screen editor has a line length limit. I decided to see if this was a limit of the eval routine as well. So I built up a list containing a giant MAKE statement and used DEFINE to turn it into a procedure. The DEFINE worked fine. The procedure ran fine. I was even able to pull it up in the screen editor just fine. However, upon exiting the editor I was greeted with a set of lovely VDP fireworks, and the system locked up. The second case is similar, but more concerning. I have been, as I said, working on routines to build up large lists -- large being a relative term. They should be pretty reasonable, all things concerned. And Logo handles working with them beautifully. However, I have discovered that any time I try and save an environment containing large lists, and then try and restore, I get the VDP fireworks. Which seems to leave me with two options: 1) Write the program to avoid long lists 2) Write a "cleanup" routine to delete all long lists before save #1 would be simpler, but would result in overall less, well, Lisp-y style code. It might be slower as well, if the parser is optimized for list handling, but as of now, it's a black box. I suppose this means some benchmarking will be necessary. #2 is ugly, kludgy, and will doubtless result in heartache when I inevitably forget to run the cleanup routine before saving. But the code should be much more elegant. And well, I like perverse hacks. I've only been at this for a few days, but I feel I'm getting farther and farther away from the goal as I chase down all of these rabbit holes. But in the end having all of this documented is more important than finishing a project.
-
Neat! You know, if you ignore the infix operators, you can get a generalized map function: TO MAP :FUNC :N :LST MAKE "ANSW [ ] TELL :LST EACH [RUN ( SENTENCE [MAKE "ANSW LPUT ] :FUNC [YOURNUMBER :N :ANSW ] ) ] OUTPUT :ANSW END PRINT MAP "SUM 5 [1 2 3 ] 6 7 8 Gimme a bit and I should be able to toss together a reduce (APL / ) too.
-
I have a toy forth/lisp hybrid I wrote in python that has turtle graphics. Which makes it PostScript, basically, as was written by a complete naif. Super fun to mess around with; I love it.
-
Well, I already have a good sized wanted feature list, despite only cracking the manual a week ago. But that's quite an undertaking for someone. Quicker and easier would be decoding the file format to at least make some modern tools to help with development; we'll see if I get frustrated enough to make that happen. I've been complaining a lot, and will continue to, I'm sure. But what it does well, it's amazing at. I don't think what I have in mind is overly ambitious, but we'll see.
-
Well, never mind. There aren't any primitives that will pass the state of the environment to a function, they only write it to screen. That's disappointing.