IRC channel logs

2014-12-18.log

back to list of logs

<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>R7RS will also be an option soon
<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>s/more/most/
<mark_weaver>davexunit: out of curiosity, what is this for?
<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.
<mark_weaver>I'd have to think about it some more.
<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>but maybe I'm missing something.
<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.
<mark_weaver>cool :)
<davexunit>so I can use the field name instead of the accessor
<mark_weaver>hmm, that might be hard
<mark_weaver>'set-fields' depends on some magic that's part of the macros that are bound to the accessors.
<mark_weaver>but the field names are not bound
<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.
<davexunit>hmm, thanks for the info.
<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 :)
<davexunit>hehe thanks, though. what you said helps.
<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.
<nalaginrut>morning guilers~
<dsmith-work>Thursday Greetings, Guilers
<ijp>happy eponalia
<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> (lambda (fileUrl)
<unclej> (let ((handle (curl-easy-init)))
<unclej>
<unclej>What's the proper way to do the call-with-output-file form?
<unclej>I'm calling single-document-download like this: (single-document-download "http://www.blah.com/testing.pdf")
<davexunit>unclej: you are quoting #t
<davexunit>change '#t to #t and try
*davexunit looks up docs for call-with-output-file
<dsmith-work>Ewww.
<dsmith-work>That is confusing.
<davexunit>?
<dsmith-work>call-with-output-file filename proc [#:encoding=#f] [#:binary=#f]
<davexunit>oh yeah, the args are in the wrong order?
<davexunit>the required args must come first
<dsmith-work>What's with the '=' in there?
<davexunit>it's just showing what the default value is.
<davexunit>it's not syntax
<davexunit>just notation for the documentation
<unclej>sorry had to go pick up my kid. trying your suggestion now.
<unclej>I unquoted the '#t:
<unclej>no love
<unclej>scheme@(guile-user)> (single-document-download "https://api.data.gov/regulations/v3/download?documentId=EPA-HQ-OAR-2013-0602-18894&attachmentNumber=1&contentType=pdf")
<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>
<unclej>Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue.
<cky>davexunit: '#t and #t evaluate to the same thing.
<unclej>scheme@(guile-user) [1]>
<unclej>thought so...
<cky>unclej: Lemme test something.
<unclej>k
<davexunit>cky: yeah, good point.
<davexunit>since it's a primitive.
<cky>unclej: You have to put the #:binary #t _after_ the lambda.
<davexunit>unclej: your arguments are in the wrong order
<davexunit>as we said before
<davexunit>cky beat me to it
<unclej>k... lemmie fix.
<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.
<davexunit>that's odd.
<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.
<davexunit>it's odd syntax, IMO.
<unclej>yeah... it worked. Much obliged.
<cky>unclej: :-D
<davexunit>cool
<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.
<davexunit>that was what I meant.
<cky>:-D
<davexunit>poor word choice.
<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> (lambda (fileUrl outfile-name)
<unclej> (let ((handle (curl-easy-init)))
<unclej> (curl-easy-setopt handle 'url fileUrl)
<unclej> (call-with-output-file
<unclej> )
<unclej> )
<unclej> )
<unclej>
<unclej>;; testing the downloader out by pulling down the ref manual in pdf format:
<unclej>(single-document-download "http://www.free-soft.org/FSM/english/issue03/guile.pdf" "guile.pdf")
<unclej>
<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>$ file guile.pdf
<unclej>guile.pdf: PDF document, version 1.2
<unclej>$ mupdf guile.pdf
<unclej>error: cannot find startxref
<unclej>warning: trying to repair broken xref
<unclej>error: invalid key in dict
<unclej>error: cannot parse dict
<unclej>warning: ignoring object with invalid object number (0 0 R)
<unclej>error: No pages in document
<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 not, then you've already got problems)
<mark_weaver>if it _is_ a bytevector, then use 'put-bytevector' to write it to the file.
<unclej>not sure... I've just been sorta bootstrapping myself from the examples at http://www.lonelycactus.com/guile-curl.html . Lemmie dig in and check it out.
<mark_weaver>put-bytevector is in (rnrs io ports)
<mark_weaver>see the "R6RS Binary Output" section of the manual
<mark_weaver>(put-bytevector <port> <bv>)
<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>ugh
<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>oh, no..
<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>yes, it wil
<unclej>ah.
<unclej>k.
<mark_weaver>but you still have to use 'put-bytevector'
<unclej>k.
<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>(use-modules (rnrs io ports))
<unclej>?
<unclej>srry... disconnected there for sec.
<mark_weaver>unclej: yes
<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>(stuff in brackets is optional)
<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)
<mark_weaver>we use it in our ecmascript parser
<mark_weaver>more information about SXML at Oleg's site: http://okmij.org/ftp/Scheme/xml.html
<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.
<mark_weaver>scanning http://okmij.org/ftp/Scheme/xml.html , it looks like entity declarations are represented as ( *ENTITY* "public-id" "system-id" )
<rekado>I'm not actually parsing XML, though, but a DTD.
<mark_weaver>ah, okay.
<mark_weaver>I don't know much about the grammar of DTDs.
<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)
<rekado>well, neither do I.
<rekado>:)
<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>yeah, I think you're right.
<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.?
<mark_weaver> http://www.tom-ridge.com/p3.html has been suggested. it might not be hard to port it to guile.
<davexunit>my parsing skills are admittedly not great.
<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>rekado: ah, cool.
<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.
<mark_weaver>I'm having trouble finding the license of https://github.com/tomjridge/p3
<rekado>but I wonder how useful that would be ... considering that slurping up characters from ports is inherently stateful.
<rekado>p3 is written in OCaml
<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>well, you can use 'port->stream' from SRFI-41
*rekado looks up SRFI-41
<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.
<rekado>same here.
<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!".
<mark_weaver>that's a good instinct!
<davexunit>indeed.
<davexunit>they are like a precious, finite resource. save them for when you really need it.
*davexunit has to go now
<rekado>mark_weaver: thanks for mentioning `port->stream'; I think this will soon become useful for me.
<mark_weaver>you're welcome!
<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> (lambda (fileUrl outfile-name)
<unclej> (let ((handle (curl-easy-init)))
<unclej> (curl-easy-setopt handle 'url fileUrl)
<unclej> (call-with-output-file
<unclej> )
<unclej> )
<unclej> )
<unclej>
<unclej>thanks for the pointer to put-bytevector.
<mark_weaver>unclej: glad to help, and thanks for the update. in the future, please use a paste service (e.g. http://paste.lisp.org/new ) for things like that though :)
<mark_weaver>(not a big deal, just for the future :)
<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. :)
<mark_weaver> http://www.lonelycactus.com/guile-curl/Procedures.html seems to suggest that it should return a bytevector directly
<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.
<mark_weaver>what version of guile-curl are you using?
<unclej>I'm using master from https://github.com/spk121/guile-curl.git actually.
*mark_weaver looks
<mark_weaver>ah, okay, he added that since the 0.3 release
<unclej>yeah... perhaps the docs are lagging a bit.
<unclej>the price of progress I guess.
<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>so it's supposed to be compatible by default.
<mark_weaver>not sure why you're seeing something different.
<mark_weaver>maybe you have an older version than what I'm looking at..
*mark_weaver looks at the commit history
<mark_weaver>ohh!!
<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.
<unclej>arg..
<mark_weaver>what you're doing here is passing the keyword #:bytevector? as the bytevector flag, which is interpreted as true.
<mark_weaver>and then the #t is the new 'header?' argument.
<mark_weaver>unclej: I think you want something like this: http://paste.lisp.org/+33Q7
<mark_weaver>(untested)
<unclej>trying it now..
<unclej>nice! worked like a charm.
<mark_weaver>cool! :)
<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.
<unclej>I got python on the brain.
<mark_weaver>heh :)
<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.)
*davexunit watches http://www.infoq.com/presentations/julia-vectors-maps-sets
<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?
<mark_weaver>well, I see they have a 'keyword-apply' procedure.
<mark_weaver>and 'make-keyword-procedure'
***soggybre1d is now known as soggybread