[racket-users] Is my model of (values) accurate?
I think I don't understand (values) very well. I expected the following to return '(1 2 3): -> (list (apply values '(1 2 3))) (list (apply values '(1 2 3))) ; result arity mismatch; ; expected number of values not received ; expected: 1 ; received: 3 ; [,bt for context] This, on the other hand, does: -> (call-with-values (lambda () (apply values '(1 2 3)) list) '(1 2 3) The best mental model I've been able to come up with is that (values) returns its results vertically but most functions expect to get them horizontally and will die if there are parallel lines of uncollected values. Under this model (call-with-values) collects values from the Y axis and pivots them back onto the X axis for consumption by regular functions. This feels like a fragile analogy though. Would someone please fill me in on how it actually works? Dave -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Is my model of (values) accurate?
On Fri, Jul 22, 2016 at 6:30 PM, David Storrs wrote: > > The best mental model I've been able to come up with is that (values) > returns its results vertically but most functions expect to get them > horizontally and will die if there are parallel lines of uncollected > values. Under this model (call-with-values) collects values from the Y > axis and pivots them back onto the X axis for consumption by regular > functions. This feels like a fragile analogy though. Would someone > please fill me in on how it actually works? > > When you do: (values ...) in a DrRacket window, it does list the values vertically, but that's probably not a very useful way to think about what `values` is. You can think of `values` as a constructor of a second-class tuple. The fact that the resultant tuple is "second-class" is very important here. You can't give a name to this tuple. For example, (define foo (values 1 2 3)) is illegal. You can't pass it as an argument to a procedure: (list (values 1 2 3)) is likewise illegal. There is, in fact, very little you can do with this tuple other than let `call-with-values` unpack it. `call-with-values` is special (like call-with-continuation is special). Its first argument, a zero-arity procedure, produces a values which are then passed *as separate arguments* -- not as a second-class tuple -- to its second argument. That's what `call-with-values` does: it translates this second-class tuple into separate procedure arguments. `call-with-values` is rarely used directly. It's far more common to use `define-values` or `let-values` (or one of its variants). For example, although you can't do: (define foo (values 1 2 3)) You can do: (define-values (a b c) (values 1 2 3)) There is one special case to keep in mind: a unary use of `values`, e.g.: (values 1) is exactly equivalent to its argument. That is, (values 1) *is exactly* 1. That's not true for any other arity of `values`. (This is also how *first*-class tuples in ML behave.) For my own part, I'm not a big fan of `values` and `call-with-values`. Their use is for returning multiple values from a procedure -- which you can also do by returning a first-class, composite piece of data, like a vector or a list. The one advantage of second-class tuples is that, because there's so little you can do with them, they're easier to give optimized representations. - Jon -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Is my model of (values) accurate?
Thanks Jon, I appreciate the clear explanation. I'm using call-with-values in database code in order to turn a list into an acceptable set of bind parameters. Here's an example: (query-exec conn "insert into foo (bar, baz) values ($1, $2)" (some-func)) some-func returns a list, '("bob", "george"). query-exec throws an exception because it wants to see two elements for the bind parameters, not a list. The solution I found was this: (call-with-values (lambda () (apply values the-list)) (curry query-exec conn stmt)) I know that I could have dug the parameters out with (car) and (cadr), but this seemed like it would be a common enough pattern that it was worth coming up with a standard answer that would work for any number of params. This is what got me thinking about how exactly (values) worked. On Fri, Jul 22, 2016 at 7:28 PM, Jon Zeppieri wrote: > > > On Fri, Jul 22, 2016 at 6:30 PM, David Storrs > wrote: > >> >> The best mental model I've been able to come up with is that (values) >> returns its results vertically but most functions expect to get them >> horizontally and will die if there are parallel lines of uncollected >> values. Under this model (call-with-values) collects values from the Y >> axis and pivots them back onto the X axis for consumption by regular >> functions. This feels like a fragile analogy though. Would someone >> please fill me in on how it actually works? >> >> > > When you do: > >(values ...) > > in a DrRacket window, it does list the values vertically, but that's > probably not a very useful way to think about what `values` is. You can > think of `values` as a constructor of a second-class tuple. The fact that > the resultant tuple is "second-class" is very important here. You can't > give a name to this tuple. For example, > >(define foo (values 1 2 3)) > > is illegal. You can't pass it as an argument to a procedure: > >(list (values 1 2 3)) > > is likewise illegal. There is, in fact, very little you can do with this > tuple other than let `call-with-values` unpack it. > > `call-with-values` is special (like call-with-continuation is special). > Its first argument, a zero-arity procedure, produces a values which are > then passed *as separate arguments* -- not as a second-class tuple -- to > its second argument. That's what `call-with-values` does: it translates > this second-class tuple into separate procedure arguments. > > `call-with-values` is rarely used directly. It's far more common to use > `define-values` or `let-values` (or one of its variants). For example, > although you can't do: > >(define foo (values 1 2 3)) > > You can do: > >(define-values (a b c) (values 1 2 3)) > > There is one special case to keep in mind: a unary use of `values`, e.g.: > >(values 1) > > is exactly equivalent to its argument. That is, (values 1) *is exactly* 1. > That's not true for any other arity of `values`. (This is also how > *first*-class tuples in ML behave.) > > For my own part, I'm not a big fan of `values` and `call-with-values`. > Their use is for returning multiple values from a procedure -- which you > can also do by returning a first-class, composite piece of data, like a > vector or a list. The one advantage of second-class tuples is that, because > there's so little you can do > with them, they're easier to give optimized representations. > > - Jon > > -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Is my model of (values) accurate?
I don't fully understand the use case... but have you looked at 'apply'? > (define (sum4 a b c d) (+ a b c d)) > (apply sum4 1 2 (list 3 4)) 10 On Fri, Jul 22, 2016 at 7:58 PM, David Storrs wrote: > Thanks Jon, I appreciate the clear explanation. > > I'm using call-with-values in database code in order to turn a list into > an acceptable set of bind parameters. Here's an example: > > (query-exec conn "insert into foo (bar, baz) values ($1, $2)" (some-func)) > > some-func returns a list, '("bob", "george"). query-exec throws an > exception because it wants to see two elements for the bind parameters, not > a list. The solution I found was this: > > (call-with-values > (lambda () (apply values the-list)) > (curry query-exec conn stmt)) > > I know that I could have dug the parameters out with (car) and (cadr), but > this seemed like it would be a common enough pattern that it was worth > coming up with a standard answer that would work for any number of params. > > This is what got me thinking about how exactly (values) worked. > > > On Fri, Jul 22, 2016 at 7:28 PM, Jon Zeppieri wrote: > >> >> >> On Fri, Jul 22, 2016 at 6:30 PM, David Storrs >> wrote: >> >>> >>> The best mental model I've been able to come up with is that (values) >>> returns its results vertically but most functions expect to get them >>> horizontally and will die if there are parallel lines of uncollected >>> values. Under this model (call-with-values) collects values from the Y >>> axis and pivots them back onto the X axis for consumption by regular >>> functions. This feels like a fragile analogy though. Would someone >>> please fill me in on how it actually works? >>> >>> >> >> When you do: >> >>(values ...) >> >> in a DrRacket window, it does list the values vertically, but that's >> probably not a very useful way to think about what `values` is. You can >> think of `values` as a constructor of a second-class tuple. The fact that >> the resultant tuple is "second-class" is very important here. You can't >> give a name to this tuple. For example, >> >>(define foo (values 1 2 3)) >> >> is illegal. You can't pass it as an argument to a procedure: >> >>(list (values 1 2 3)) >> >> is likewise illegal. There is, in fact, very little you can do with this >> tuple other than let `call-with-values` unpack it. >> >> `call-with-values` is special (like call-with-continuation is special). >> Its first argument, a zero-arity procedure, produces a values which are >> then passed *as separate arguments* -- not as a second-class tuple -- to >> its second argument. That's what `call-with-values` does: it translates >> this second-class tuple into separate procedure arguments. >> >> `call-with-values` is rarely used directly. It's far more common to use >> `define-values` or `let-values` (or one of its variants). For example, >> although you can't do: >> >>(define foo (values 1 2 3)) >> >> You can do: >> >>(define-values (a b c) (values 1 2 3)) >> >> There is one special case to keep in mind: a unary use of `values`, e.g.: >> >>(values 1) >> >> is exactly equivalent to its argument. That is, (values 1) *is exactly* >> 1. That's not true for any other arity of `values`. (This is also how >> *first*-class tuples in ML behave.) >> >> For my own part, I'm not a big fan of `values` and `call-with-values`. >> Their use is for returning multiple values from a procedure -- which you >> can also do by returning a first-class, composite piece of data, like a >> vector or a list. The one advantage of second-class tuples is that, because >> there's so little you can do >> with them, they're easier to give optimized representations. >> >> - Jon >> >> > -- > You received this message because you are subscribed to the Google Groups > "Racket Users" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to racket-users+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Is my model of (values) accurate?
On Fri, Jul 22, 2016 at 7:58 PM, David Storrs wrote: > Thanks Jon, I appreciate the clear explanation. > > I'm using call-with-values in database code in order to turn a list into > an acceptable set of bind parameters. Here's an example: > > (query-exec conn "insert into foo (bar, baz) values ($1, $2)" (some-func)) > > some-func returns a list, '("bob", "george"). query-exec throws an > exception because it wants to see two elements for the bind parameters, not > a list. The solution I found was this: > > (call-with-values > (lambda () (apply values the-list)) > (curry query-exec conn stmt)) > Okay, so `some-func` produces a list, and you want that lists elements to be provided as the last N arguments to query-exec. This is really what `apply` is good for: (apply query-exec conn "insert ..." (some-func)) should work for your case. -Jon -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Is my model of (values) accurate?
On 07/22/2016 07:58 PM, David Storrs wrote: Thanks Jon, I appreciate the clear explanation. I'm using call-with-values in database code in order to turn a list into an acceptable set of bind parameters. Here's an example: (query-exec conn "insert into foo (bar, baz) values ($1, $2)" (some-func)) some-func returns a list, '("bob", "george"). query-exec throws an exception because it wants to see two elements for the bind parameters, not a list. The solution I found was this: (call-with-values (lambda () (apply values the-list)) (curry query-exec conn stmt)) You can also write that as just (apply query-exec conn stmt the-list) so your example above would be (apply query-exec conn "insert into foo (bar, baz) values ($1, $2)" (some-func)) Ryan -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Is my model of (values) accurate?
*sigh* Just when I was feeling clever, I discover I missed the obvious. ;> Thanks, everyone. On Fri, Jul 22, 2016 at 8:05 PM, Ryan Culpepper wrote: > On 07/22/2016 07:58 PM, David Storrs wrote: > >> Thanks Jon, I appreciate the clear explanation. >> >> I'm using call-with-values in database code in order to turn a list into >> an acceptable set of bind parameters. Here's an example: >> >> (query-exec conn "insert into foo (bar, baz) values ($1, $2)" (some-func)) >> >> some-func returns a list, '("bob", "george"). query-exec throws an >> exception because it wants to see two elements for the bind parameters, >> not a list. The solution I found was this: >> >> (call-with-values >> (lambda () (apply values the-list)) >> (curry query-exec conn stmt)) >> > > You can also write that as just > > (apply query-exec conn stmt the-list) > > so your example above would be > > (apply query-exec > > conn > "insert into foo (bar, baz) values ($1, $2)" > (some-func)) > > Ryan > > -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.