<Profpatsch>I see. It’s just very daunting to have all that stuff lying around (especially in a highly dynamic language where a slight mistake might slip unnoticed). <davexunit>is it okay to use guile's "historical record API" for record type introspection? <davexunit>and by "okay" I mean "not going to deprecated soon". <mark_weaver>Profpatsch: fwiw, I agree with you. I have two solutions to offer you. <mark_weaver>(1) write your code as a set of R6RS libraries, importing only the specific bindings you need from (guile) <mark_weaver>(2) write a set of normal guile modules, but write (define-module (blah blah) #:pure ...) <mark_weaver>like R6RS libraries, that will exclude all but the more fundamental syntax forms from the default namespace in that module, so you'll again have to import just what you need. <mark_weaver>for now, my recommendation would be to use R6RS plus selected bindings from (guile). <mark_weaver>the most future proof way would probably be to use (rnrs records inspection (6)) <mark_weaver>the historical record API is certainly not going anywhere, although I'm reluctant to promise to keep SRFI-9 records compatible with it. <davexunit>mark_weaver: I basically want to write something that works like inheritable fields in ludo's define-record-type* <davexunit>but I'm hoping to do so in a much simpler way, if possible. <davexunit>mark_weaver: I have an immutable data type with a bunch fields and I'd like to be able to inherit from one instance and tweak a field or two easily. <davexunit>writing something similar to racket's functional picture API <mark_weaver>would our new functional record setters not do what you want? (maybe with some syntax layered on top) <mark_weaver>inheriting an instance and tweaking a field or two sounds like 'set-fields' from (srfi srfi-9 gnu) <davexunit>yeah I think some syntax on top of those is what I want <mark_weaver>I put a lot of effort into making 'set-fields' as efficient as I could. <davexunit>I basically want set-fields, with different syntax. <davexunit>so I can use the field name instead of the accessor <mark_weaver>'set-fields' depends on some magic that's part of the macros that are bound to the accessors. <mark_weaver>to be efficient, set-fields needs to know (at compile time) which record type it's working with. and that depends on storing that information in the accessor macro. <mark_weaver>(although the accessors are supposed to be procedures, they are actually macros that pretend to be procedures) <mark_weaver>IIRC, there's no way to find out the record type from the field name. <davexunit>I was going to specialize it for just one particular type. <mark_weaver>unless I'm mistaken, I see no problem with making the field names the same as the accessor names. <mark_weaver>but I confess that I don't remember the details very well. that knowledge is swapped out :) <mark_weaver>I think the field names are only used within a particular define-record-type form, and have no significance or binding outside. <mark_weaver>iirc, their only purpose is to allow the constructors arguments to be matched up with the associated fields. <unclej>hi guys. Trying to use call-with-output-file to write out a pdf to file. Having trouble with the optional argument for #:binary. Here's the code: <unclej>(define single-document-download <unclej> (let ((handle (curl-easy-init))) <unclej>What's the proper way to do the call-with-output-file form? *davexunit looks up docs for call-with-output-file <dsmith-work>call-with-output-file filename proc [#:encoding=#f] [#:binary=#f] <davexunit>it's just showing what the default value is. <unclej>sorry had to go pick up my kid. trying your suggestion now. <unclej>ice-9/boot-9.scm:872:0: In procedure call-with-output-file: <unclej>ice-9/boot-9.scm:872:0: Invalid keyword: #t <unclej>Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue. <cky>davexunit: '#t and #t evaluate to the same thing. <cky>unclej: Lemme test something. <cky>unclej: You have to put the #:binary #t _after_ the lambda. <davexunit>unclej: your arguments are in the wrong order <davexunit>optional args must go after the required ones <cky>I tested with (call-with-output-file "/dev/null" newline #:binary #t) and it worked. <cky>davexunit: IIRC in Racket keyword args can go anywhere. <cky>davexunit: It's not odd, Racket handles keywords differently from how Guile does it. Guile treats keywords much like CL does: just a special type of symbol you can pass around. In Racket, you cannot "pass keywords around" without quoting them first. The dispatcher handles keywords at a much lower level. <unclej>yeah... it worked. Much obliged. <cky>davexunit: Also, the reason you can use #t instead of '#t is not because it's a primitive, it's because it's self-evaluating. There are primitives (like ()) that are not self-evaluating. <cky>In R7RS, vector literals are self-evaluating, unlike R5RS. In R5RS, unquoted vector literals in the code is invalid (and there are implementations like Chicken that won't allow it). <cky>Trivia of the day. :-) <unclej>Anyone have any intel on how to download a binary (e.g. pdf ) and write to file? I'm using the following: <unclej>; Download and write out a binary file <unclej>(define single-document-download <unclej> (let ((handle (curl-easy-init))) <unclej> (curl-easy-setopt handle 'url fileUrl) <unclej>;; testing the downloader out by pulling down the ref manual in pdf format: <unclej>and the resulting guile.pdf file is a string. <unclej>It has the pdf content in there wrapped in double quotes. <unclej>when I remove the quotes it gets recognized by the 'file' utility on OpenBSD as a pdf but I can't open it with any of the readers. <unclej>the downloading is performed by guile-curl <unclej>guile.pdf: PDF document, version 1.2 <unclej>warning: trying to repair broken xref <unclej>warning: ignoring object with invalid object number (0 0 R) <unclej>mupdf: error: cannot open document <fangism>[fink-announce] guile20-2.0.11 packaged for darwin9 (tested on powerpc) <mark_weaver>unclej: I'm not familiar with the guile curl bindings. what type of object does 'curl-easy-perform' return? <mark_weaver>if it's a binary file, the returned object better be a bytevector, I guess. <mark_weaver>if it _is_ a bytevector, then use 'put-bytevector' to write it to the file. <unclej>from the docs on guile-curl: 'With Guile-2.0, its default behavior is to return a string containing the resource. There is no way to handle the encoding of the string: the binary data will mapped byte-by-byte to a string containing codepoints U+0000 through U+00FF. If the optional bytevector? parameter is given and is set to #t, the resource will be returned as a bytevector.' <mark_weaver>well, okay. in that case you should use 'display' instead of 'write'. <unclej>hrrrrmmm.. so lemmie try to set that bytevector? parameter. <mark_weaver>yes, set the bytevector? parameter, and then use 'put-bytevector'. <mark_weaver>remember, the arguments of 'put-bytevector' are reversed compared with those of 'write'. <unclej>the call-with-output-file won't handle bytevectors when #:binary is set to #t? <mark_weaver>'write' would instead print the bytevector as text, like #vu8(0 40 50 ...) <unclej>how do I pull in rnrs io ports? I'm just a week or so into guile scheme.. <unclej>srry... disconnected there for sec. <rekado>I'm looking for a convenient way to parse some text from a port. Are there any more parser functions than read-char, peek-char, find-string-from-port?, etc that would make this a little easier? <rekado>the file I want to process contains XML declarations and I really just want to parse the entity declarations. <rekado>something like this: <!ENTITY [%] name [SYSTEM|PUBLIC publicID] resource [NDATA notation] > <rekado>I find it tedious to read-char/peek-char repeatedly, put back stuff to the port after deciding that it's not the token I thought it was ... <rekado>resource is a quote-delimited string, which might contain #\\>, so I can't just read up to the closing angled bracket and then match a regular expression over the string. <rekado>I feel like I'm missing something about how to navigate in ports. <mark_weaver>rekado: we have functions to convert betwen xml into something called sxml. <mark_weaver>I don't know off hand how entity declarations are represented in sxml though. <mark_weaver>see Guile Modules -> SXML in the manual for some basics. there's more information on Oleg's site. <mark_weaver>we also have a LALR parser generator in (system base lalr) <rekado>Yeah, I know about SXML and I've read a lot of the stuff Oleg has published. <rekado>I find the SSAX code to be very dense, though. <rekado>I'm not actually parsing XML, though, but a DTD. <rekado>I was hoping I simply overlooked a few handy functions; I didn't want to write a full-blown parser (even though Oleg's work makes this a lot easier) <mark_weaver>Oleg's stuff might have a DTD parser included, dunno. <rekado>as far as I can see the SSAX stuff does not contain a DTD parser, also inline declarations are dropped. <rekado>comments on xml->sxml say that this might be a future enhancement. <mark_weaver>guile could really use a nice set of parser combinators built in. <rekado>are there any external libraries providing parser combinators that you know of? <rekado>(I come from a Haskell background and I enjoyed parsec / attoparsec a lot) <mark_weaver>I don't know of one that's available for guile currently. <davexunit>mark_weaver: agreed. then I could write that markdown parser in a straightforward way. :) <davexunit>for those that have looked at parser combinator implementations: how difficult are they to comprehend, write, port, etc.? <rekado>for a markdown parser there's peg-markdown whose grammar might be translated to scheme with guile's built-in lalr parser generator. <davexunit>ideally, I'd like a markdown parser that not only works, but is elegant. <davexunit>iirc, the scheme lalr module isn't functional, which is a bummer. <rekado>I suppose we could build a monadic parser library on top of guile-monad. <rekado>it would feel imperative but desugar to purely functional code. <rekado>but I wonder how useful that would be ... considering that slurping up characters from ports is inherently stateful. <rekado>isn't that far removed from scheme and closer to statically typed languages like Haskell? <davexunit>I don't worry about stuff like reading from ports. <mark_weaver>scheme code is often written in a purely-functional style, in fact we encourage it. <davexunit>I try my best to save the imperative stuff for more low-level tasks, and make sure that high-level APIs use a functional style. <davexunit>and I like that scheme lets me just do that without a fight. <mark_weaver>the lack of static type system may or may not be a complication when porting code from ML-style languages. often it is not. <rekado>I always feel like I'm doing something wrong when I'm tempted to write "set!". <davexunit>they are like a precious, finite resource. save them for when you really need it. <rekado>mark_weaver: thanks for mentioning `port->stream'; I think this will soon become useful for me. <mark_weaver>just beware that it won't be as efficient as doing it the uglier way, but it may not be a problem here, since I guess DTDs aren't too big. <unclej>@mark: Got the binary download to work now: <unclej>@mark: ; Download and write out a binary file <unclej>(define single-document-download <unclej> (let ((handle (curl-easy-init))) <unclej> (curl-easy-setopt handle 'url fileUrl) <unclej>thanks for the pointer to put-bytevector. <mark_weaver>interesting, so 'curl-easy-perform' returns a list with the bytevector as the second element? <unclej>Sorry guy. Been a long time since I've been on IRC. I'll make sure to use that in the future. :) <unclej>yeah.. seems like it should but no go. I had to use cadr to get at the bytevector. <unclej>the car of what was returned ended up being header. ***linas_ is now known as linas
<unclej>not sure what's up with those docs for guile-curl but easy enough to figure it out in the geiser repl. <unclej>yeah... perhaps the docs are lagging a bit. <mark_weaver>there's actually a third 'header?' argument which is supposed to default to #f, of whether you want that list or just the body. <mark_weaver>maybe you have an older version than what I'm looking at.. *mark_weaver looks at the commit history <unclej>just checked it out like a week ago. <mark_weaver>unclej: you're calling curl-easy-perform incorrectly <mark_weaver>the bytevector argument is an _optional_ argument, not a keyword argument. <unclej>arg.. :) sounds like par for the course when I'm involved. <mark_weaver>what you're doing here is passing the keyword #:bytevector? as the bytevector flag, which is interpreted as true. <unclej>Still trying to get the hang of the optional vs. keyword args thing. <mark_weaver>yeah, there's a bit of a learning curve when coming from other languages. <mark_weaver>you didn't get an error before because of two facts: (1) keywords are just ordinary values that can be passed as normal arguments to procedures. they are only interpreted specially if the called procedure is looking for them. (2) for historical reasons inherited from lisp, *any* value can be interpreted as a boolean in scheme. anything that's not #f is considered true. <mark_weaver>I'm not sure that (1) is a mistake. it allows more flexibility, but is a double-edged sword. <mark_weaver>I think that (2) was a mistake, but it's far too late to change that. <mark_weaver>but (2) can be convenient at times, and lispers and schemers make use of it quite regularly to make code more concise. <unclej>I'll def keep that one in mind. 10 bucks says I've got that happening in other parts of my code too. <cky>mark_weaver: In contrast, Racket does not have (1), which while less flexible (you can't throw keywords around in a list to send to apply), also means you can have keywords anywhere in the expression and have it work as expected. :-) <cky>mark_weaver: (In particular, in Racket, for keyword _values_, they must be quoted.) <mark_weaver>cky: yeah, I can definitely see the benefits to racket's approach. it's a trade-off. <mark_weaver>cky: how do you call a procedure with a dynamically determined set of keyword arguments in racket? <mark_weaver>what can you do with quoted keywords in racket besides pass them around and store them? ***soggybre1d is now known as soggybread