<BW^->davexunit,civodul,*: so is there any POSIX thread support to start with? <BW^->POSIX thread support.. yes? <BW^->so Guile does POSIX threads *only* and does *not* do any green threads atop of that, right? <dsmith-work>BW^-: Right, unless you implement them yourself using delimited continuations. <BW^->dsmith-work: wait, there's call/cc right <BW^->dsmith-work: or what do you mean by delimited here, why mention it at all? <ft>BW^-: Delimited continuations are documented under "Prompts" in the manual. <ft>API Ref. → Control Mechanisms → Prompts <BW^->ft: the point here is just to get call/cc but at a lower CPU expense, right? <turbofail>no, the point is to get a more useful control flow than what call/cc would normally give you <BW^->turbofail: what different in semantics here? <BW^->turbofail: i never really understood what delimited continuations do or are of value for - <BW^->turbofail: as I got it, their point was to put less stress on CPU or heap than call/cc <BW^->the stack trace needed for creating the instance would be more superficial, and the stack frames it binds would be limited (unlike the unlimited for call/cc) <turbofail>the simplest illustration of the difference is doing something like (define c (call/cc (lambda (k) k))). if you look at c now, you'll see a continuation object. but then if you call (c 5), and then look at c again, you'll see that c is now 5 <turbofail>whereas if you did (define c (reset (shift k k))) and did (c 5), it will return 5, and then when you evaluate c again you'll still have that continuation there <turbofail>because the continuation no longer includes the define <turbofail>this ends up being a lot more useful, because the fact that call/cc captures the entire rest of the program is really inconvenient. you end up stomping on parts of the program you didn't intend to <turbofail>the more important part of it is not just the fact that it only captures part of the control stack, but also that it lets you transplant that portion of the control stack wherever you want, whereas call/cc is kind of "rooted" <BW^->turbofail: can you clarify your last point, re transplant vs rooted? <turbofail>you can kind of fake a delimited continuation by combining call/cc with a bunch of set! statements, but it's not a good way to do it, and i don't think it's possible to get it entirely right <BW^->turbofail: okay, (begin (define c (call/cc (lambda (k) k))) (define d (print "Hello world\\n"))) <BW^->so (c 5) prints Hello world again - okay. <BW^->turbofail: again I don't understand your last point :) <BW^->transplant? root? what :)) <turbofail>when you call the continuation c, it ends up re-executing everything that happened after you captured the continuation, redefining c in the process and re-running your print statement <BW^->and shift/reset does.. ? <turbofail>because it captured the whole continuation. it means you can't ever really capture any value that you might have wanted to return from that "suspended process" <turbofail>well i mean you can, but you have to use some ugly set! tricks <BW^->turbo: like, double call/cc:s ? <BW^->turbo: can you give me a minimum useful example of shift/reset ? <turbofail>you can the shift/reset continuation as many times as you want without losing track of it <turbofail>but another example is, let's say you're mapping over a list, but you want to be able to take a break in the middle of it for some reason <BW^->turbofail: so the shift/reset continuation is "delimited" in that it won't capture more than up to the point where it was made?? <turbofail>yes, the reset delimits the point up to which is captured <turbofail>anyway back to the map example, you could do (define foo (reset (map (lambda (x) (shift k (vector x k))) my-list))) <turbofail>and this would return a vector containing the first element of the list, and a continuation that you can supply a new value to <turbofail>upon supplying that new value, you'd get back the next element of the list and a new continuation <turbofail>this basically turns `map' into a resumable iterator over a list <BW^->turbofail: i'm 100% sure call/cc can be used for this <BW^->but sure, this code you suggested now is a slightly shorter route for that purpose <turbofail>and like i said, you'll have to resort to some set! trickery <BW^->turbofail: i would think shift/reset can be implemented in terms of call/cc? <turbofail>perhaps it can, but it's not a good way to implement it <turbofail>regardless it could only ever be the same on a single-threaded system, as the call/cc implementation would make heavy use of mutation <turbofail>the other important point is that the map iterator that we returned here is pure - you can restart it at any point just by saving an earlier continuation <turbofail>you might be able to fake such a thing with the call/cc/set! hackery, but i don't remember if i was able to do it completely <turbofail>anyway, call/cc is certainly wrong for green threads. threads shouldn't include the portion of the call stack that created them <turbofail>also, fun fact, the naive implementation of this map iterator using call/cc only works at the REPL because the continuation is already getting delimited by your scheme implementation <BW^->turbofail: so the shift/reset "continuation" keeps an "address pointer" for you? <turbofail>well "naive" meaning "completely wrong" in this case <BW^->(whereas for call/cc, reinvocations of k *always lead to the same address*)? <turbofail>sure. you could think of it as, delimited continuations accept an extra "return continuation" that they use instead of the one they captured initially <BW^->turbofail: so I see reset/shift as a special-case of call/cc <turbofail>if you were implementing a scheme compiler in continuation passing style, you would use 2 continuation arguments insetad of one in order to implement delimited continuations <BW^->turbofail: you mean, at the fundamental CPS transformation level? <turbofail>because that's pretty much how the semantics of it work <turbofail>it's not really a special case, it's more like call/cc is just a special case of shift/reset with a reset enclosing the whole program <BW^->turbofail: ok, so if I have ana rbitrary scheme implementation with call/cc support, <BW^->turbofail: if I want to implement shift/reset I need to add an extra continuation argument for this into the CPS transformation <turbofail>well many scheme compilers don't do a CPS transformation at all <BW^->turbofail: those without call/cc, right. <turbofail>no, plenty of them with call/cc still don't do a CPS transformation <BW^->turbofail: but what do they do? <BW^->turbofail: isn't that expensive? <BW^->turbofail: what's the reasoning, that shift and call/cc is rare <BW^->turbofail: but execution of CPS-transformed code is not expensive is it? <BW^->it's rather a question of cost during compilation..?? <BW^->turbofail: ok, thanks for the conversation <BW^->turbofail: wait - call/cc is not completely a special case of shift/reset <BW^->shift/reset has an updating address pointer in it, no? <BW^->so sure, call/cc could be counted as a shift/reset with a reset around the whole program <BW^->shift/reset can also be implemented in terms of call/cc, and then that wrapper would implement the address pointer part too. ***BW^- is now known as BW^-_
***BW^-_ is now known as BW^-
<cmhobbs>can someone point me to examples of standalone guile applications (read: not extensions)? <nalaginrut>cmhobbs: but I'm not sure if you need a standalone program included Guile static linked? <cmhobbs>i was just interested in examples that could be executed as is <cmhobbs>and i just discovered the examples/ directory in the source <turbofail>BW^-: shift/reset doesn't have to have any sort of "updating address pointer," unless you count a normal procedure call as having one. it behaves more like a regular procedure call in that it simply returns to the caller <turbofail>which is what i was getting at when i said you're "transplanting part of the call stack" <turbofail>anyway the discussion of whether call/cc can implement shift/reset is kind of irrelevant because the fact remains that it is a bad way to do it <ArneBab>turbofail: I guess you mean that it has disadvantages, right? <ArneBab>(calling something “a bad way to do it” doesn’t sound like a strong argument) <ArneBab>sneek: later tell davexunit: I think I should have used your coroutine for the wisp reader. That would likely have been much cleaner: Create a function which only gets new expressions when the list of unprocessed expressions is empty. <turbofail>ArneBab: yeah. to me those two phrases mean the same thing. but anyway, that link that bipt gave pretty much summarizes all those disadvantages <nalaginrut>I wonder if lambda-calculus based IR can be used for imperative-languages anyway, although it's proper for FP in natural <nalaginrut>I saw Appel's paper said "they are both doing exactly same thing in different notation" *davexunit just used guile and guile-curl to do some FSF work :) <davexunit>just a small import script that makes some http api calls, but still fun. <sneek>davexunit, you have 1 message. <sneek>davexunit, ArneBab says: I think I should have used your coroutine for the wisp reader. That would likely have been much cleaner: Create a function which only gets new expressions when the list of unprocessed expressions is empty. <davexunit>ArneBab: hmmm, coroutines for a reader. interesting. <davexunit>ArneBab: The (system repl coop-server) module in guile 2.0.11 uses prompts (what my coroutines are made from) to implement a REPL server. <civodul>davexunit: yay for Guile at the FSF! :-) <civodul>keep doing it, so they'll have to hire you forever ;-) <davexunit>civodul: I'm only using it for one-off things right now, because I can write scheme 1000x faster than php or whatever. <unknown_lamer>are signals delivered to guile threads via asyncs? I have a critical section where I am spitting data out to a serial port and a partial message will cause my program to permanently desync <unknown_lamer>I've ... managed to create a workaround (kill function that locks the serial port lock before killing), but it is a paaaaain when hitting C-c in the repl during testing <cky>unknown_lamer: I have an even better workaround for you. It's called SIG_IGN. :trollface: <unknown_lamer>I should probably make my microcontroller code more robust :( <dsmith-work>unknown_lamer: I've been living in PIC 23H land for the last 6 months. <dsmith-work>I worked on a micro with 2K of program flash, and 128 bytes of ram. And half of that was stack. 64K is a luxury at that level. <dsmith-work>unknown_lamer: The cool thing is you own the machine down to the last bit. <taylanub>scheme@(guile-user)> (list-matches (make-regexp "foo$" regexp/extended) "foo\\n") <taylanub>scheme@(guile-user)> (list-matches (make-regexp "foo\\n$" regexp/extended) "foo\\n") <taylanub>never mind. I needed `regexp/newline' as an argument to `make-regexp'. <taylanub>I need a channel full of rubber ducks. :) <ArneBab>Is there a way to auto-parallelize list-ec (from SRFI-42) <ArneBab>I just implemented my first ensemble square root filter in Guile - function parameter estimation from uncertain measurements. <ArneBab>But I have lots of list-ec calls in there, and I’d like to make them multithreaded :) <cky>That depends on whether Guile has a thread pool system built in. If so, making a thread pool implementation of eager comprehensions shouldn't be too onerous. <civodul>but ISTR there's an open bug in that area... <ArneBab>civodul: then I’d better delay that till tomorrow… <civodul>did you try to get Geiser support for wisp? <ArneBab>civodul: not yet - I’d like to get the SRFI done first. <ArneBab>civodul: also I need to find a way to store the line-numbers when reading the file (I know it’s possible, I just didn’t manage to do it yet)