2022-12-01 03:32:52 Who's doing advent of code in Forth this year then? 2022-12-01 10:37:13 Finally tried Joy (by Thun), there is absolutely no way to use a named variable. :) 2022-12-01 10:37:42 I'm sure it could have been better, but here's the Advent of Code 2022 day 1: https://gist.githubusercontent.com/neuro-sys/346a69c9c1df4ec6ed7d403aba42f0a7/raw/7c96449e33f20c50fb84da60f65bbea02025b298/12.txt 2022-12-01 10:45:10 No variables? What is it, functional or something? 2022-12-01 10:45:34 or assembly 2022-12-01 10:45:42 You can read here: https://www.kevinalbrecht.com/code/joy-mirror/forth-joy.html 2022-12-01 10:45:49 I've learned to appreciate the "concept" of functional programming, but it is so esoteric I kind of shudder to think about trying to do anything really useful that way. 2022-12-01 10:45:54 Also here https://en.wikipedia.org/wiki/Joy_(programming_language) 2022-12-01 10:46:09 "Side effects" are usually what I'm most interested in when I program. I write programs to DO STUFF. 2022-12-01 10:46:13 It is a purely theoretical toy, but pretty fun. 2022-12-01 10:46:18 closures or returning function pointers can be handy 2022-12-01 10:47:08 Yeah, I do think function pointers can be handy. I think of that as what Forth definitions are "made of." Lists of pointers. 2022-12-01 10:47:10 I imagine retroforth and factor are inspired by it. 2022-12-01 10:47:15 also not diddling with global state so much 2022-12-01 10:47:31 Yeah, but see above about "doing stuff." 2022-12-01 10:47:44 If you're controlling hardware, then your global state is likely to be the state of your hardware. 2022-12-01 10:47:49 Or an image of it, I mean. 2022-12-01 10:48:15 You can't just "declare" a new piece of hardware and have it be there. 2022-12-01 10:48:38 I.e., your hardware is "global." 2022-12-01 10:48:53 enterprise stuff allows hotswap 2022-12-01 10:49:13 Yes, it is possible to have lots of hardware, so you might want to have lots of images. 2022-12-01 10:49:34 So being able to encapsulate it in a structure that you can reproduce is good. 2022-12-01 10:49:36 however having first class functions or Forth case words makes certain tasks easier to program 2022-12-01 10:50:51 : a ... ;; 2022-12-01 10:50:53 : b ... ;; 2022-12-01 10:50:55 : c ... ;; 2022-12-01 10:50:57 : foo switch a b c ; 2022-12-01 10:52:04 Or, if you want a bit of error protection 2022-12-01 10:52:11 : foo 3 min switch a b c ; 2022-12-01 10:52:21 Maybe umin 2022-12-01 10:53:00 I don't really use that to any extent, but it's easy enough to do. 2022-12-01 11:12:44 I see that some people use GPT-3 to solve the problems: https://i.imgur.com/icdb7J2.png 2022-12-01 14:44:23 how should I implement the dictionary in C? 2022-12-01 14:44:35 and how I represent the data for a word? 2022-12-01 14:44:55 I think in something kind of a list of numbers + switch xD 2022-12-01 14:45:39 I would use function pointers, but not for builtins in the core 2022-12-01 14:45:59 I did mine in an array, with each entry holding a "cell" that calls out one definition entry. 2022-12-01 14:46:11 more likely for additional stuff like for example making a module or something 2022-12-01 14:46:26 Trying to remember more specifics - that one was several years ago. 2022-12-01 14:46:41 And it wound up fairly ugly, but it did work, and it did run "like a real Forth." 2022-12-01 14:46:44 KipIngram: my initial idea was to have an array of int pointers like int * dictionary[26] 2022-12-01 14:47:01 The primitives were hard coded lines of C, that ended in a proper NEXT sequence. 2022-12-01 14:47:24 for the letters in the alphabet, so they'd be stored by the initial letter 2022-12-01 14:47:43 KipIngram: how is the relation from the dictionary to the hardcoded line of C? 2022-12-01 14:48:07 NEXT was something like, um, w=*(ip++); followed by something that jumped me to where the contents of w pointed. 2022-12-01 14:48:18 That double indirection is the indirect threading. 2022-12-01 14:48:20 oh, so labels and goto? 2022-12-01 14:48:33 Yes, pointers to labels. 2022-12-01 14:48:52 I was thinking in goto 2022-12-01 14:48:57 Which is an extended feature of the gcc compiler - not standard C. 2022-12-01 14:49:14 I could go with just labels and goto label 2022-12-01 14:49:21 Right - I did no calls whatsoever; machine code wise it just ran around this little set of code lines that did my primitives> 2022-12-01 14:49:29 Except for when I did a syscall for OS service. 2022-12-01 14:49:44 also for the dictionary I'd like some sort of hash table instead of a linked list 2022-12-01 14:50:04 I was pretty happy to be able to get that close to "correct Forth operation" using a C compiler. 2022-12-01 14:50:13 hahha correct forth 2022-12-01 14:50:18 ACTION looks at his code 2022-12-01 14:50:26 Then you won't be able do FORGET. 2022-12-01 14:50:32 Unless you keep a side list. 2022-12-01 14:50:38 https://termbin.com/v0e8 2022-12-01 14:50:48 the interpret_word function is kind of a joke 2022-12-01 14:50:55 but I'm even wondering if doing that xD 2022-12-01 14:50:58 What I may try there someday, on platforms with RAM to spare, is a linked list but also a hash table I populate on the fly. 2022-12-01 14:51:09 like for example storing words in the dictionary by len 2022-12-01 14:51:18 I have several stacks too 2022-12-01 14:51:20 So first use of a word will require linked list search, but that will get a hash entry made and subsequent uses will find it that way. 2022-12-01 14:51:22 and a type stack 2022-12-01 14:51:25 Sort of like memoizing. 2022-12-01 14:51:43 maybe is time to have a return stack 2022-12-01 14:51:43 I've t hought about type stacks. 2022-12-01 14:51:53 but these days I think of one stack which holds object pointers. 2022-12-01 14:52:00 And the type will reside with the objects. 2022-12-01 14:52:02 KipIngram: the "standard" solution is a union 2022-12-01 14:52:06 which I dislike 2022-12-01 14:52:12 also a void * stack 2022-12-01 14:52:13 But the pointer gets you to it, so it gets you to the type, the value, everything. 2022-12-01 14:52:34 but the void pointer stack forces me to allocate bytes for every integer xD 2022-12-01 14:52:36 Isn't a union just two different "type ways" of refering to the same memory? 2022-12-01 14:52:54 Like giving a variable two names that have different properties? 2022-12-01 14:53:08 a union makes the biggest type be the size of that "cell" 2022-12-01 14:53:10 What do you dislike about it? 2022-12-01 14:53:26 which means it will always take the biggest size 2022-12-01 14:53:30 I dislike that 2022-12-01 14:53:34 I see. 2022-12-01 14:54:10 I shouldn't worry about this, but idk why I do 2022-12-01 14:54:15 I just dislike it 2022-12-01 14:54:28 I have some things like that. 2022-12-01 14:54:34 and does not seem like a good solution, but maintaining several stacks does not seem better 2022-12-01 14:54:35 "Personal hangups." 2022-12-01 14:54:51 well the real explaination is "I'm an asshole" 2022-12-01 14:54:52 xD 2022-12-01 14:55:32 I should not care about the fact a union will take the biggest size 2022-12-01 14:55:40 The main advantage of "one stack' in Forth is that words know where to get their operands and where to put their results. You could certainly have each of your words still know that, even while using an array of stacks. 2022-12-01 14:55:48 but I dislike it so I won't be happy with that 2022-12-01 14:55:51 It's just that then it would always be that way, every time you call the word. 2022-12-01 14:56:32 also a stack won't be initialized unless you put data on it 2022-12-01 14:56:57 but I have to think about the dictionary 2022-12-01 14:57:19 I'd like to have some sort of compiling that gives some performance 2022-12-01 14:57:41 but seems it will be goto label 2022-12-01 14:57:46 Well, what I like about the linked list + memoized hash approach is that it's entirely optional. 2022-12-01 14:58:07 You get a Forth that can behave in a totally standard way, but also get the performance boost of a hash table if you have the resources for it. 2022-12-01 14:58:12 I'm fine with a hash instead of a linked list 2022-12-01 14:58:17 I don't need forget 2022-12-01 14:58:25 and will never be a real forth, not even close 2022-12-01 14:58:25 And that means you can make the hash table big enough to make collisions as unlikely as you please. 2022-12-01 14:59:05 but I'd like to not use external dependencies and I won't be able to make a good hash algorithm 2022-12-01 14:59:06 Ok, well, that's fair. The size of hash table you need will depend on your tolerance of collisions. 2022-12-01 14:59:26 I'm really thinking about indexing them by length 2022-12-01 14:59:50 Sure - the length should be part of matching. 2022-12-01 14:59:53 I'll always have the len of the word, so I can use it 2022-12-01 15:00:10 I just match the whole string, including the count byte. 2022-12-01 15:00:19 and being C I hope I can get acceptable performance no matter the way I choose 2022-12-01 15:00:27 I have a primitive that does that with rep cmpsb. 2022-12-01 15:00:31 but the dictionary is the most important thing to get right 2022-12-01 15:00:42 also the compiling of words 2022-12-01 15:01:01 it's the major bottleneck, at least I've noticed that in the perl implementation 2022-12-01 15:01:12 Consider a field with some unused bits in your dictionary headers. 2022-12-01 15:01:30 You're almost bound to think of some wrinkle you might like to add that needs you to specify whether a word has that feature or not. 2022-12-01 15:01:41 Having a few bits to spare in the header makes that a lot easier. 2022-12-01 15:01:53 well for now I assume I'll get a prototype 2022-12-01 15:01:56 Do you have "immediate" words? 2022-12-01 15:02:01 not really 2022-12-01 15:02:11 Those are words that execute right now, even when you're compiling. 2022-12-01 15:02:20 Those usually have a bit in the header set. 2022-12-01 15:02:21 they execute at read time, but there's no sense of an immediate word 2022-12-01 15:02:42 as I have very few immediate words, the immediate words call the other immediate ones when they find them 2022-12-01 15:02:47 And I have an extra bit I use to tell the compiler whether or not the word needs an offset back to the start of the definition compiled after it. 2022-12-01 15:02:58 but I wondered about having a sense of immediate word 2022-12-01 15:03:08 also with the number of elements they return 2022-12-01 15:03:19 for example [ is an immediate word that returns a list 2022-12-01 15:03:38 And one for words that I will want to have "hidden" after I do my first .wipe (the words .: and .wipe let me implement a "temporary helper word" feature in my system). 2022-12-01 15:03:43 having immediate words would allow the user make new ones and be used from the builtins 2022-12-01 15:04:00 Words that are useful for building the worDS I'm really interested in, but then I want them gone from the dictionary. 2022-12-01 15:04:10 the only thing I'd like to have is some sort of internal variables 2022-12-01 15:04:37 Not sure what you mean by that. 2022-12-01 15:04:39 hmm temporary words 2022-12-01 15:04:52 KipIngram: some feature that for example lets me write accumulators 2022-12-01 15:05:19 a variable that resides between executions, but does not mess with the environment 2022-12-01 15:05:38 say a closure 2022-12-01 15:05:52 Ok. I'm probably not imagining your use case properly. 2022-12-01 15:06:03 a closure might be the use case 2022-12-01 15:06:12 something that works like a closure 2022-12-01 15:06:20 that has internal bindings 2022-12-01 15:06:23 My old HP calculator used to have a "LastX" register; if I ran a function like + or sin() or whatever, it would copy the input X register to LastX before doing the op. 2022-12-01 15:06:31 And the LastX command would pull it back. 2022-12-01 15:06:39 I sometimes think about adding that to my system. 2022-12-01 15:06:51 But I'm low on registers now, and that would certainly need to be one. 2022-12-01 15:07:05 And it's not a standard Forth word. 2022-12-01 15:07:25 And it slows down practically everything a small beat. 2022-12-01 15:08:13 I want the dictionary be able to get function pointers, but another thing for builtins of the 'core' 2022-12-01 15:08:41 also I have to think about how to implement lists 2022-12-01 15:09:12 I'm thinking in having a one type list, and linked lists to have any kind of data 2022-12-01 15:09:27 the one type would be just a pointer like int * list 2022-12-01 15:09:37 it would only allow integers 2022-12-01 15:09:43 same for chars and floats, etc 2022-12-01 15:10:01 but if you want to have a list with several kinds of data, then a linked list 2022-12-01 15:10:57 I suppose the dictionary will do something with goto 2022-12-01 15:11:02 I don't have better ideas xD 2022-12-01 15:11:32 I was thinking in making words be a list of numbers 2022-12-01 15:11:41 and some switch case 2022-12-01 15:12:22 I know I'll have to try different ways and make several versions of this lang in C until I get things clearer 2022-12-01 15:13:00 I'll take a shower, thanks KipIngram for the hints 2022-12-01 15:13:02 <3 2022-12-01 15:13:16 Oh, an... 2022-12-01 15:13:24 Well, there he went. :-) 2022-12-01 15:14:05 Having defined words "functionally different" from built-in words is definitely not something I'd want in a Forth-like system. That's one of its beauties. 2022-12-01 15:14:36 recently ive been embracing distinction between user and system functions, but not in fortj 2022-12-01 15:14:42 i think it has its place also 2022-12-01 15:15:09 I suppose; I'm just not prepared to take my Forth in that direction. 2022-12-01 15:15:35 I just love that "consistency of interface," bottom to top. 2022-12-01 15:40:00 6 months before John Backus died. Pretty old and tired already, but still there're interesting bits. Especially his "defeat" with FP. https://www.youtube.com/watch?v=dDsWTyLEgbk 2022-12-01 16:25:38 Oh, that seems bound to have some good stuff in it. 2022-12-01 16:25:58 I like stuff from those "pioneer people.' 2022-12-01 16:36:43 it's a real shame because FP was actually genius. 2022-12-01 16:37:28 KipIngram: that's totally fair! 2022-12-01 16:38:45 Um, pardon y ignorance, but what is FP standing for here? 2022-12-01 16:38:59 FORTRAN PROGRAMMING 2022-12-01 16:39:08 hahaha. 2022-12-01 16:39:08 oh wait, functional 2022-12-01 16:39:11 nah. 2022-12-01 16:39:25 F# ? 2022-12-01 16:39:28 the distinction between user and system really shines in languages like K and APL 2022-12-01 16:39:31 not in the traditional sense. https://en.wikipedia.org/wiki/FP_(programming_language) 2022-12-01 16:39:40 wherein you have a set of 'primitives' 2022-12-01 16:40:10 primitives are 'system functions' - they are not implemented in terms of anything else, and they are represented with one character 2022-12-01 16:40:17 each primitive is designed to work with one another 2022-12-01 16:40:46 oh, special forms, only less readable 2022-12-01 16:40:46 the characteristic of "writing out the full subprogram is easier than writing out the label for it" is interesting. low semantic gap. 2022-12-01 16:40:55 special forms? 2022-12-01 16:40:59 yes! 2022-12-01 16:41:03 i love it 2022-12-01 16:41:04 sum:+/ 2022-12-01 16:41:08 same. 2022-12-01 16:41:10 When I dipped into APL a few months ago I did find the way things would work with one another to be powerful, but it also seemed to call for quite a lot of memorization. Same symbol might mean different things, depending on exactly how it's used. 2022-12-01 16:41:16 yes 2022-12-01 16:41:20 K takes that to an extreem 2022-12-01 16:41:29 if y'all want to play with a compiler and a full implementation, here's FP: https://web.archive.org/web/20180106183517/http://www.call-with-current-continuation.org/fp/ 2022-12-01 16:41:47 It struck me as a "once you know it, it's powerful as hell, but it'll take a while" kind of things. 2022-12-01 16:41:59 i find that it's really intuitive, a lot of the K overloads 2022-12-01 16:42:22 That would certainly help. 2022-12-01 16:42:32 for instance, K has an operator, / 2022-12-01 16:42:36 Any kind of "pattern" to things would help. 2022-12-01 16:43:01 +/ is the common case - called with a function that takes two arguments, it is 'reduce', or 'fold' 2022-12-01 16:43:15 Yeah, I got familiar with that one in APL. 2022-12-01 16:43:27 it's important to realise that +/ is a function of itself 2022-12-01 16:43:39 if you call +/ with one argument, you get fold 2022-12-01 16:43:49 if you call it with two, you get 'seeded fold' 2022-12-01 16:44:12 +/1 2 3 is 6, 5+/1 2 3 is 11 2022-12-01 16:44:38 Well, see, I read that last one as the +/ still making 6, and then 5 gets added. 2022-12-01 16:44:43 yes 2022-12-01 16:44:49 that's how you're meant to read it 2022-12-01 16:45:05 but the way it works is that +/ is invoked with two arguments 2022-12-01 16:45:08 jesus FP is dense. 2022-12-01 16:45:24 +/[5;1 2 3] is the same as 5+/1 2 3 2022-12-01 16:45:28 So +/1 2 3 is like 0+/1 2 3 2022-12-01 16:45:35 same as 1+2 is +[1;2] 2022-12-01 16:45:43 mhm 2022-12-01 16:45:56 non-seeded fold provides an identity 2022-12-01 16:46:06 for multiplication, it's 1 2022-12-01 16:46:17 1*/1 2 3 and */1 2 3 are the same 2022-12-01 16:46:36 Ah, yes - same idea, but with the proper starting point for the operation. 2022-12-01 16:46:50 mhm 2022-12-01 16:46:56 So if there's no left argument, identity is assumed. 2022-12-01 16:47:05 yes! 2022-12-01 16:47:42 now, if you provide a function that takes a single argument to /, you get something called 'fixpoint' 2022-12-01 16:47:50 run the function on the result until it stops changing 2022-12-01 16:48:11 Right. Know about fixpoint. 2022-12-01 16:48:33 so, if you provide a second argument to a fixpointed function 2022-12-01 16:48:37 you get 'n-do' 2022-12-01 16:48:43 which applies that function n times 2022-12-01 16:48:54 The after-measurement state of quantum systems is a fixpoint wavefunction (fixfunction? eigenfunction?) of the observable operator. 2022-12-01 16:49:07 5 ,:/1 will apply ,: to 1 5 times 2022-12-01 16:49:18 Because it's very much like taking the starting quantum state and hitting with the observable operator over and over until it stops changing. 2022-12-01 16:49:31 ,:/5 will loop infinitely, because it never converges 2022-12-01 16:49:36 Except there can be more than one such function, and which one you get is a coin toss. 2022-12-01 16:49:47 i never learned quantum stuff 2022-12-01 16:49:56 now, here's where it starts being fun 2022-12-01 16:49:59 I only know enough to get myself in trouble. 2022-12-01 16:50:06 if you provide a function instead of an integer 2022-12-01 16:50:09 you get 'while' 2022-12-01 16:50:32 which is the same as n-do, but rather than repeating n times, it repeats so long as the second function is true 2022-12-01 16:50:36 for instance 2022-12-01 16:50:50 {x<5} (1+)/0 2022-12-01 16:51:04 this will apply 1+ as long as the result is less than 5 2022-12-01 16:51:18 How does it know to bind x to that meaning? 2022-12-01 16:51:27 Could I put y? Or is x special somehow? 2022-12-01 16:51:37 x is the default first argument 2022-12-01 16:51:41 It had omega (w) and some other symbol that were special symbols. 2022-12-01 16:51:48 if you put y, then the function would have two arguments 2022-12-01 16:51:49 APL did at least - maybe K changes that. 2022-12-01 16:51:51 this is K, not APL 2022-12-01 16:51:56 Right - gotcha. 2022-12-01 16:52:01 {x+1} has one argument, because it has x 2022-12-01 16:52:15 {[y]y+1} also has one argument, because you named that one argument 2022-12-01 16:52:27 default arguments go up to 3; beyond that you have to name them 2022-12-01 16:52:32 It's clear what they were trying to do. They were trying to turbocharge math nomenclature. 2022-12-01 16:52:41 And from what I can tell, they succeeded. 2022-12-01 16:52:42 (1st is x, second is y, third is z) 2022-12-01 16:52:47 That aspect of it made a lot of sense to me. 2022-12-01 16:52:52 turbocharge? pretty sure you need nitrogen for that 2022-12-01 16:52:56 now, here's where the overload stuff gets really interesting 2022-12-01 16:53:01 we have 5 cases of / 2022-12-01 16:53:06 We all walk around all the time highly familiar with these abstract symbols + - * / 2022-12-01 16:53:14 These languages just try to extend that. 2022-12-01 16:53:19 the three cases of / with a single arg function are not related to the two arg 2022-12-01 16:53:34 however, every case of / is related to every case of \ 2022-12-01 16:53:55 See, that was where it started to lose a little glitter to me - when it started having a symbol have entirely different meanings in different situations. 2022-12-01 16:54:04 hence memorization. 2022-12-01 16:54:12 specifically, where / produces one result, \ produces the intermediate results 2022-12-01 16:54:19 Things to just "remember." 2022-12-01 16:54:24 not much memorisation is needed honestly 2022-12-01 16:54:28 Which is exactly what we do with + - * / 2022-12-01 16:54:43 can you folk see screenshots on here? 2022-12-01 16:54:46 That little + symbol doesn't really MEAN "add" in any way, except that we've learned it does. 2022-12-01 16:54:51 so now it does 2022-12-01 16:55:00 ACTION uploaded an image: (1KiB) < https://libera.ems.host/_matrix/media/v3/download/the-apothecary.club/63f9f3cb971262d3e9ddf66910c7bb889de2f4c7/image.png > 2022-12-01 16:55:23 ACTION uploaded an image: (1KiB) < https://libera.ems.host/_matrix/media/v3/download/the-apothecary.club/4aafa43f03a7a6ed6465a7d25ccd994d3c57c5e9/image.png > 2022-12-01 16:55:43 ACTION uploaded an image: (1KiB) < https://libera.ems.host/_matrix/media/v3/download/the-apothecary.club/0d3a0c6062596a9841395f91135aff65be7d0d0b/image.png > 2022-12-01 16:55:57 -, when applied with only one argument, is negate 2022-12-01 17:38:51 So, one thiing that makes Forth work particularly smoothly is the fact that primitives run without affecting the return stack. It means that when they want to manipulate it, they don't have to move their own "return address" out of the way and put it back after. 2022-12-01 17:40:19 E.g., if (;) needed a return address, it would find that return address covering up the item it wants to eliminate from the that stack. 2022-12-01 17:41:13 So that flies in the face of what I said earlier about words we add working 'exactly the same' as words already there. There is this difference in nature of primitives vs. definitions.