I'm still getting used to multiple return values. What's the easiest
way to make a list that contains month and year from a universal-time?
I can do this, but it seems horribly verbose for what it does:
(multiple-value-bind
(second minute hour date month year day daylight-p zone)
(decode-universal-time timestamp)
(list month year))
Ari.
--
Elections only count as free and trials as fair if you can lose money
betting on the outcome.
K. Ari Krupnikov wrote:
> I'm still getting used to multiple return values. What's the easiest
> way to make a list that contains month and year from a universal-time?
>
> I can do this, but it seems horribly verbose for what it does:
>
> (multiple-value-bind
> (second minute hour date month year day daylight-p zone)
> (decode-universal-time timestamp)
> (list month year))
>
> Ari.
>
Hmm. I got:
(defun nths (indices list)
(loop for i in indices
collecting (nth i list)))
(nths '(4 5) (multiple-value-list (decode-universal-time timestamp)))
Perhaps it might be worth making a function like
(get-time-fields (:month :year) (decode-universal-time timestamp))
If you'll be splitting apart times a lot.
Hi,
Nathan Baum <···········@btinternet.com> writes:
> K. Ari Krupnikov wrote:
>> I'm still getting used to multiple return values. What's the easiest
>> way to make a list that contains month and year from a universal-time?
>> I can do this, but it seems horribly verbose for what it does:
>> (multiple-value-bind
>> (second minute hour date month year day daylight-p zone)
>> (decode-universal-time timestamp)
>> (list month year))
>> Ari.
>
> Hmm. I got:
>
> (defun nths (indices list)
> (loop for i in indices
> collecting (nth i list)))
>
> (nths '(4 5) (multiple-value-list (decode-universal-time timestamp)))
While that solution has the advantage to work at runtime, macrology
helps even more if one does not need that flexibility. For example,
(binding-some-values ((4 month) (5 year))
(decode-universal-time timestamp)
(list month year))
can be transformed using ('cond-let' is described below):
(defmacro binding-some-values (some-bindings form &body body)
(labels ((collect-bindings (index bindings ignored)
(cond-let (_ (minusp index)
(values bindings ignored))
(entry (assoc index some-bindings)
(collect-bindings (1- index)
(cons (second entry) bindings)
ignored))
(_ t
(let ((symbol (gensym "IGNORED-VALUE-")))
(collect-bindings (1- index)
(cons symbol bindings)
(cons symbol ignored)))))))
(multiple-value-bind (bindings ignored)
(collect-bindings (reduce #'max some-bindings :key #'car) nil nil)
`(multiple-value-bind ,bindings
,form
(declare (ignore ,@ignored))
,@body))))
Maybe using positional parameters is more intuitive:
(multiple-value-bind*
(_ _ _ _ month year)
(decode-universal-time 0)
(list month year))
Such a form is transformable by:
(defmacro multiple-value-bind* (maybe-vars form &body body)
(let ((pairs (mapcar (lambda (symbol)
(if (eq symbol '_)
(let ((ignored (gensym "IGNORED-VALUE-")))
(cons ignored ignored))
(cons symbol nil))) maybe-vars)))
`(multiple-value-bind
,(mapcar #'car pairs)
,form
(declare (ignore ,@(remove nil (mapcar #'cdr pairs))))
,@body)))
Here is the 'cond-let' utility used in 'binding-some-values':
(defmacro cond-let (&rest clauses)
"Syntax: COND-LET {no-binding-clause | binding-clause}* => result*
no-binding-clause ::= (_ test-form form*)
binding-clause ::= (var test-form form*)
COND-LET is similar to COND, but allows binding the result of the
test forms. The expansion of 'clause' depends on its first
element:
* _: No binding is established, 'test-form' and 'form*' are used
exactly like in COND;
* Other symbol: a new binding is established between that symbol
and the result of evaluating 'test-form'; the 'form*' forms
are executed using that binding when its value is not NIL."
(when clauses
(destructuring-bind (clause . other-clauses) clauses
(destructuring-bind (binding test-form &body body) clause
(flet ((gen-1 (test)
`(if ,test (progn ,@body) (cond-let ,@other-clauses))))
(case binding
(_
(gen-1 test-form))
(otherwise
`(let ((,binding ,test-form))
,(gen-1 binding)))))))))
Cu,
Damien.
--
http://foobox.net/~dash/
I can resist everything except temptation.
--Oscar Wilde
> I can do this, but it seems horribly verbose for what it does:
>
> (multiple-value-bind
> (second minute hour date month year day daylight-p zone)
> (decode-universal-time timestamp)
> (list month year))
This is slightly less verbose:
(multiple-value-bind (s m h d mn yr)
(decode-universal-time timestamp)
(declare (ignorable (s m h d)))
(list (mn yr)))
You don't need to bind to any variables beyond the last one you're
interested in.
-jeff cunningham
From: K. Ari Krupnikov
Subject: Re: (month year) from universal-time
Date:
Message-ID: <86pss6bjep.fsf@deb.lib.aero>
Jeff Cunningham <·······@cunningham.net> writes:
> You don't need to bind to any variables beyond the last one you're
> interested in.
Ah! Thank you. I missed that fact.
Still verbose, but a little shorter.
Ari.
--
Elections only count as free and trials as fair if you can lose money
betting on the outcome.