Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Trying to grasp this line of code.

157 views
Skip to first unread message

neilharp...@gmail.com

unread,
Sep 27, 2011, 9:19:09 PM9/27/11
to
I am learning lisp as my first language. I am reading through
Practical common lisp.

This is the block thats confusing me:

(defun dump-db ()
(dolist (cd *db*)
(format t "~{~a:~10t~a~%~}~%" cd)))

dolist loops through the list *db* with the 'cd' variable right?

'~a' prints the list in a more readable format. but what about ~{, I
dont get what thats doing.

Thanks.

Rob Warnock

unread,
Sep 27, 2011, 10:38:36 PM9/27/11
to
neilharp...@googlemail.com <neilharp...@gmail.com> wrote:
+---------------
| ... I am reading through Practical common lisp.
| This is the block thats confusing me:
|
| (defun dump-db ()
| (dolist (cd *db*)
| (format t "~{~a:~10t~a~%~}~%" cd)))
|
| dolist loops through the list *db* with the 'cd' variable right?
|
| '~a' prints the list in a more readable format. but what about ~{,
| I dont get what thats doing.
+---------------

(*sigh*) Did you read the text *IMMEDIATELY BELOW* the code you quoted?!?

http://www.gigamonkeys.com/book/practical-a-simple-database.html/dump-db
...
Admittedly, the FORMAT call is a little cryptic. However, FORMAT
isn't particularly more complicated than C or Perl's printf function
or Python's string-% operator. In Chapter 18 I'll discuss FORMAT
in greater detail. For now we can take this call bit by bit.
...
Now things get slightly more complicated. When FORMAT sees ~{ the next
argument to be consumed must be a list. FORMAT loops over that list,
processing the directives between the ~{ and ~}, consuming as many
elements of the list as needed each time through the list.
...


-Rob

-----
Rob Warnock <rp...@rpw3.org>
627 26th Avenue <http://rpw3.org/>
San Mateo, CA 94403

Jason Earl

unread,
Sep 27, 2011, 11:42:35 PM9/27/11
to
For the full story you probably want to see:

http://www.lispworks.com/documentation/HyperSpec/Body/22_c.htm

Or you could just keep reading Chapter 3 of Practical Common Lisp as it
covers this bit. In fact, this is what it says:

Now things get slightly more complicated. When FORMAT sees ~{ the
next argument to be consumed must be a list. FORMAT loops over
that list, processing the directives between the ~{ and ~},
consuming as many elements of the list as needed each time
through the list. In dump-db, the FORMAT loop will consume one
keyword and one value from the list each time through the
loop. The ~% directive doesn't consume any arguments but tells
FORMAT to emit a newline. Then after the ~} ends the loop, the
last ~% tells FORMAT to emit one more newline to put a blank line
between each CD.

If reading that doesn't make things clear then the thing to do is fire
up a repl and play around with something like this:

(format t "~{~a:~10t~a~%~}~%" '(one two three four))

Now try adding things to the list at the end. Just remember there are
two ~a directives that consume values from the list so you will want to
add things in pairs (although testing what happens with an odd number is
probably useful).

Basically the ~{ ~} pair will iterate over the values in the list until
it is empty. Then you will get a final extra newline "~%".

Jason

neilharp...@gmail.com

unread,
Sep 28, 2011, 7:53:11 AM9/28/11
to
On Sep 28, 4:42 am, Jason Earl <je...@notengoamigos.org> wrote:
Thanks that helps, I did read the next part of the book of course, but
I never understood it.

Jason Earl

unread,
Sep 28, 2011, 10:09:50 AM9/28/11
to
Format strings are a lot more powerful than the same facilities in other
languages. I am a newbie to Lisp too, and find them quite hard to
read. I never expect iterative directives or conditional directives
that are handled in the format string instead of in code.

Like I said, I am still enough of a Lisp newbie that when I see an
example like that it makes me pine for a straight forward for loop.

However, like most of the stuff in Practical Common Lisp it shows how
just a little lisp-fu can go a long way. A little bit of playing at it
becomes clear what the ~{ ~} construct does, and it certainly saves a
lot of code.

Jason

Tim Bradshaw

unread,
Sep 28, 2011, 10:55:23 AM9/28/11
to
On 2011-09-28 15:09:50 +0100, Jason Earl said:

> Like I said, I am still enough of a Lisp newbie that when I see an
> example like that it makes me pine for a straight forward for loop.

What we don't tell you, of course, is that all serious lisp code now
consists entirely of complex format strings. Of course, the so-called
"standard" doesn't tell you most of the more, er, interesting features
- we had to suppress those after the accident. Some older people still
insist on working with loop arcana, but that's not really fashionable
now.

smh

unread,
Sep 29, 2011, 10:06:43 PM9/29/11
to
> However, FORMAT
>     isn't particularly more complicated than C or Perl's printf function
>     or Python's string-% operator.

Umm, yes it is.

Tim Bradshaw

unread,
Sep 30, 2011, 6:49:56 AM9/30/11
to
On 2011-09-30 03:06:43 +0100, smh said:

> Umm, yes it is.

Indeed, it is. But mostly it's more complex in useful ways: things like
being able to write "~{~A~^, ~}" are significantly useful facilities.

Steve Graham

unread,
Sep 30, 2011, 9:12:50 AM9/30/11
to
Which accident was that?

Tim Bradshaw

unread,
Sep 30, 2011, 10:11:30 AM9/30/11
to
On 2011-09-30 14:12:50 +0100, Steve Graham said:

> Which accident was that?

I believe there is some chance that the documents may be declassified,
though I am sure not in my lifetime. I was merely an observer -
fortunately a distant one - all those directly involved died at the
scene, or shortly afterwards. I still have nightmares.

WJ

unread,
Feb 18, 2012, 2:34:18 PM2/18/12
to
neilharp...@googlemail.com wrote:

> I am learning lisp as my first language. I am reading through
> Practical common lisp.
>
> This is the block thats confusing me:
>
> (defun dump-db ()
> (dolist (cd db)
> (format t "~{~a:~10t~a~%~}~%" cd)))
>
> dolist loops through the list db with the 'cd' variable right?
>
> '~a' prints the list in a more readable format. but what about ~{, I
> dont get what thats doing.
>
> Thanks.

The function should not be operating on a global variable.
And the format statement is too obfuscated.

MatzLisp:

$db =
[[:TITLE, "Home", :ARTIST, "Dixie Chicks", :RATING, 9, :RIPPED, true],
[:TITLE, "Fly", :ARTIST, "Dixie Chicks", :RATING, 8, :RIPPED, true],
[:TITLE, "Roses", :ARTIST, "Kathy Mattea", :RATING, 7, :RIPPED, true]]

def dump_db( db )
db.each{|cd|
cd.each_slice(2){|k,v|
print "#{ k }:".ljust( 10 )
puts v }
puts }
end

dump_db( $db )

==>
TITLE: Home
ARTIST: Dixie Chicks
RATING: 9
RIPPED: true

TITLE: Fly
ARTIST: Dixie Chicks
RATING: 8
RIPPED: true

TITLE: Roses
ARTIST: Kathy Mattea
RATING: 7
RIPPED: true

Kaz Kylheku

unread,
Feb 19, 2012, 2:22:15 AM2/19/12
to
On 2012-02-18, WJ <w_a_...@yahoo.com> wrote:
> neilharp...@googlemail.com wrote:
>
>> I am learning lisp as my first language. I am reading through
>> Practical common lisp.
>>
>> This is the block thats confusing me:
>>
>> (defun dump-db ()
>> (dolist (cd db)
>> (format t "~{~a:~10t~a~%~}~%" cd)))
>>
>> dolist loops through the list db with the 'cd' variable right?
>>
>> '~a' prints the list in a more readable format. but what about ~{, I
>> dont get what thats doing.
>>
>> Thanks.
>
> The function should not be operating on a global variable.
> And the format statement is too obfuscated.

According to the author of Ruby, it is the "Perlification" of Lisp.
That is a near synonym for "obfuscation".

Your program is four times as long and has about the the obfuscation.
You're just diluting the obfuscation with verbiage.

The format is not hard to understand. ~{ ... ~} denotes repetition
over the list, ~a is argument substitution, ~10t means tab to the 10th
column, and ~% is newline.

> MatzLisp:
>
> $db =
> [[:TITLE, "Home", :ARTIST, "Dixie Chicks", :RATING, 9, :RIPPED, true],
> [:TITLE, "Fly", :ARTIST, "Dixie Chicks", :RATING, 8, :RIPPED, true],
> [:TITLE, "Roses", :ARTIST, "Kathy Mattea", :RATING, 7, :RIPPED, true]]

Obfuscated. Why all the commas, and why can't we just assign to "db"
rather than "$db"? What does the sygil achieve? There does not appear
to be any ambiguity that it solves over just

db = [[...]]

> def dump_db( db )
> db.each{|cd|

Why no $ sygil on this db?

> cd.each_slice(2){|k,v|
> print "#{ k }:".ljust( 10 )
> puts v }
> puts }
> end

This is longer and more complicated than

(defun dump-db (db)
(dolist (cd db)
(format t "~{~a:~10t~a~%~}~%" cd)))

Furthermore, the format solution could be shortened more, since another level
of ~{ .. ~} will replace the dolist. We end up with this nice one-liner:

(format t "~{~{~a:~10t~a~%~}~}" db)

I will take this over a "Fortranification of Logo".

And in case you're dumb enough to keep your CD database in this Ruby jail,
here is how you can bust it out.

It's easier in TXR to parse the raw data out of your Ruby source code
than for Ruby to work with the objects "natively".

$ cat cd.txr
@(collect)
@(coll):@prop, @(cases)"@val"@(or)@val@/[\], ]/@(end)@(end)
@(end)
@(output)
@ (repeat)
@ (repeat)
@{`@prop:` 10} @val
@ (end)

@ (end)
@(end)

$ txr cd.txr cd.rby
TITLE: Home
ARTIST: Dixie Chicks
RATING: 9
RIPPED: true

TITLE: Fly
ARTIST: Dixie Chicks
RATING: 8
RIPPED: true

TITLE: Roses
ARTIST: Kathy Mattea
RATING: 7
RIPPED: true

$ cat cd.rby

Barry Margolin

unread,
Feb 19, 2012, 8:35:05 PM2/19/12
to
In article <201202182...@kylheku.com>,
Kaz Kylheku <k...@kylheku.com> wrote:

> On 2012-02-18, WJ <w_a_...@yahoo.com> wrote:
> > neilharp...@googlemail.com wrote:
> >
> >> I am learning lisp as my first language. I am reading through
> >> Practical common lisp.
> >>
> >> This is the block thats confusing me:
> >>
> >> (defun dump-db ()
> >> (dolist (cd db)
> >> (format t "~{~a:~10t~a~%~}~%" cd)))
> >>
> >> dolist loops through the list db with the 'cd' variable right?
> >>
> >> '~a' prints the list in a more readable format. but what about ~{, I
> >> dont get what thats doing.
> >>
> >> Thanks.
> >
> > The function should not be operating on a global variable.
> > And the format statement is too obfuscated.
>
> According to the author of Ruby, it is the "Perlification" of Lisp.
> That is a near synonym for "obfuscation".

Except that FORMAT predates Perl by many years.

Compact notations for output formatting are common in many languages.
FORMAT does take it to an extreme, though -- not too many others have
built-in looping and conditionals. Although I admit that when I'm
writing Perl I really miss it -- I'd really prefer to use ~[~;~] in the
format string than using the ?: operator in the argument list.

--
Barry Margolin, bar...@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***

Pascal J. Bourguignon

unread,
Feb 19, 2012, 9:38:52 PM2/19/12
to
Barry Margolin <bar...@alum.mit.edu> writes:
> Compact notations for output formatting are common in many languages.
> FORMAT does take it to an extreme, though -- not too many others have
> built-in looping and conditionals. Although I admit that when I'm
> writing Perl I really miss it -- I'd really prefer to use ~[~;~] in the
> format string than using the ?: operator in the argument list.

And format is great for localization.

(let ((person (make-person :title-code 0 :first-name "Pascal"
:initials "J" :surname "Bourguignon")))
(dolist (*language* '(:en :fr))
(format t (ecase *language*
(:en "~[Mr.~;Mrs.~;Miss~;Dr.~] ~A ~A. ~A~%")
(:fr "~[M.~;Mme~;Mlle~;Dr.~] ~:@(~3@*~A~) ~1@*~A~%"))
(title-code person) (first-name person)
(initials person) (surname person))))
prints:

Mr. Pascal J. Bourguignon
M. BOURGUIGNON Pascal

Try to do that in Fortran or with C printf!

--
__Pascal Bourguignon__ http://www.informatimago.com/
A bad day in () is better than a good day in {}.

Antony

unread,
Feb 21, 2012, 2:10:14 AM2/21/12
to
On 2/19/2012 6:38 PM, Pascal J. Bourguignon wrote:
> And format is great for localization.
>
> (let ((person (make-person :title-code 0 :first-name "Pascal"
> :initials "J" :surname "Bourguignon")))
> (dolist (*language* '(:en :fr))
> (format t (ecase *language*
> (:en "~[Mr.~;Mrs.~;Miss~;Dr.~] ~A ~A. ~A~%")
> (:fr "~[M.~;Mme~;Mlle~;Dr.~] ~:@(~3@*~A~) ~1@*~A~%"))
> (title-code person) (first-name person)
> (initials person) (surname person))))
> prints:
>
> Mr. Pascal J. Bourguignon
> M. BOURGUIGNON Pascal
>
Could you explain this a bit, at least point out the main part that I
need to look through in CLHS. Every time I look at format I give up.

Asking, cause I ended up writing my own 'positional' argument format
mechanism.
-Antony

Pascal J. Bourguignon

unread,
Feb 21, 2012, 5:33:04 AM2/21/12
to
Antony <remove+spam...@gmail.com> writes:

> On 2/19/2012 6:38 PM, Pascal J. Bourguignon wrote:
>> And format is great for localization.
>>
>> (let ((person (make-person :title-code 0 :first-name "Pascal"
>> :initials "J" :surname "Bourguignon")))
>> (dolist (*language* '(:en :fr))
>> (format t (ecase *language*
>> (:en "~[Mr.~;Mrs.~;Miss~;Dr.~] ~A ~A. ~A~%")
>> (:fr "~[M.~;Mme~;Mlle~;Dr.~] ~:@(~3@*~A~) ~1@*~A~%"))
>> (title-code person) (first-name person)
>> (initials person) (surname person))))
>> prints:
>>
>> Mr. Pascal J. Bourguignon
>> M. BOURGUIGNON Pascal
>>
> Could you explain this a bit, at least point out the main part that I
> need to look through in CLHS. Every time I look at format I give up.

You need to read the whole FORMAT sections.
http://www.lispworks.com/documentation/HyperSpec/Body/22_c.htm


> Asking, cause I ended up writing my own 'positional' argument format
> mechanism.

Clearly redundant.

Marco Antoniotti

unread,
Feb 21, 2012, 5:17:38 AM2/21/12
to
Amatuer!

On Monday, February 20, 2012 3:38:52 AM UTC+1, Pascal J. Bourguignon wrote:
> Barry Margolin <bar...@alum.mit.edu> writes:
> > Compact notations for output formatting are common in many languages.
> > FORMAT does take it to an extreme, though -- not too many others have
> > built-in looping and conditionals. Although I admit that when I'm
> > writing Perl I really miss it -- I'd really prefer to use ~[~;~] in the
> > format string than using the ?: operator in the argument list.
>
> And format is great for localization.
>
> (let ((person (make-person :title-code 0 :first-name "Pascal"
> :initials "J" :surname "Bourguignon")))
> (dolist (*language* '(:en :fr))
> (format t (ecase *language*
> (:en "~[Mr.~;Mrs.~;Miss~;Dr.~] ~A ~A. ~A~%")
> (:fr "~[M.~;Mme~;Mlle~;Dr.~] ~:@(~3@*~A~) ~1@*~A~%"))
> (title-code person) (first-name person)
> (initials person) (surname person))))

(defun print-person-title (fn sn in tc)
(let ((person (make-person :title-code tc :first-name fn
:initials in :surname sn)))
(loop for language in '(:en :fr :it)
as language-index from 0
do
(format t "~[~
~[Mr.~;Mrs.~;Miss~;Dr.~] ~A ~A. ~A~%~;~
~[M.~;Mme~;Mlle~;Dr.~] ~:@(~4@*~A~) ~2@*~A~%~;~
~[Sig.~;Sig.ra~;Sig.na~;dott.~] ~@(~4@*~A~) ~2@*~A~%~:;~
Lup. Mann. ~@(~4@*~A~) ~2@*~A~%~
~]"
language-index
(title-code person)
(first-name person)
(initials person)
(surname person)))))

Cheers
--
MA

Kaz Kylheku

unread,
Feb 21, 2012, 5:53:31 AM2/21/12
to
On 2012-02-20, Barry Margolin <bar...@alum.mit.edu> wrote:
> In article <201202182...@kylheku.com>,
> Kaz Kylheku <k...@kylheku.com> wrote:
>
>> On 2012-02-18, WJ <w_a_...@yahoo.com> wrote:
>> > neilharp...@googlemail.com wrote:
>> >
>> >> I am learning lisp as my first language. I am reading through
>> >> Practical common lisp.
>> >>
>> >> This is the block thats confusing me:
>> >>
>> >> (defun dump-db ()
>> >> (dolist (cd db)
>> >> (format t "~{~a:~10t~a~%~}~%" cd)))
>> >>
>> >> dolist loops through the list db with the 'cd' variable right?
>> >>
>> >> '~a' prints the list in a more readable format. but what about ~{, I
>> >> dont get what thats doing.
>> >>
>> >> Thanks.
>> >
>> > The function should not be operating on a global variable.
>> > And the format statement is too obfuscated.
>>
>> According to the author of Ruby, it is the "Perlification" of Lisp.
>> That is a near synonym for "obfuscation".
>
> Except that FORMAT predates Perl by many years.

According to the author of Ruby, Ruby is the perlification of Lisp, not
format.

Marco Antoniotti

unread,
Feb 21, 2012, 7:51:33 AM2/21/12
to
Ok. Where is the penal code on my desk? Let's unleash the hordes (of lawyers) to fight such a crime :)
--
Cheers

MA

Antony

unread,
Feb 21, 2012, 9:25:51 AM2/21/12
to
On 2/21/2012 2:33 AM, Pascal J. Bourguignon wrote:
> Antony<remove+spam...@gmail.com> writes:
>
>> On 2/19/2012 6:38 PM, Pascal J. Bourguignon wrote:
>>> And format is great for localization.
>>>
>>> (let ((person (make-person :title-code 0 :first-name "Pascal"
>>> :initials "J" :surname "Bourguignon")))
>>> (dolist (*language* '(:en :fr))
>>> (format t (ecase *language*
>>> (:en "~[Mr.~;Mrs.~;Miss~;Dr.~] ~A ~A. ~A~%")
>>> (:fr "~[M.~;Mme~;Mlle~;Dr.~] ~:@(~3@*~A~) ~1@*~A~%"))
>>> (title-code person) (first-name person)
>>> (initials person) (surname person))))
>>> prints:
>>>
>>> Mr. Pascal J. Bourguignon
>>> M. BOURGUIGNON Pascal
>>>
>> Could you explain this a bit, at least point out the main part that I
>> need to look through in CLHS. Every time I look at format I give up.
>
> You need to read the whole FORMAT sections.
> http://www.lispworks.com/documentation/HyperSpec/Body/22_c.htm
>
You made me read quite a bit and skim through the whole of it!
The relevant section is
22.3.7.1
~n@* goes to the nth arg, where 0 means the first one; n defaults to 0,
so ~@* goes back to the first arg. Directives after a ~n@* will take
arguments in sequence beginning with the one gone.
>
>> Asking, cause I ended up writing my own 'positional' argument format
>> mechanism.
>
> Clearly redundant.
I am not sure about having ~n@* in the i18n files, but might be worth
since then I have full format power.

Thanks,
-Antony

Aleksej Saushev

unread,
Feb 26, 2012, 5:59:32 AM2/26/12
to
It would be interesting to see how you handle languages where there's
either full name or initials and where titles like "doctor" come after
surname (Russian, Ukrainian, Belarusian).

It would be interesting to see how you handle languages where surname
goes before first name (Hungarian, Russian in another, perhaps even
prevalent, style).


--
HE CE3OH...

Tamas Papp

unread,
Feb 26, 2012, 8:04:43 AM2/26/12
to
On Sun, 26 Feb 2012 14:59:32 +0400, Aleksej Saushev wrote:

> It would be interesting to see how you handle languages where there's
> either full name or initials and where titles like "doctor" come after
> surname (Russian, Ukrainian, Belarusian).
>
> It would be interesting to see how you handle languages where surname
> goes before first name (Hungarian, Russian in another, perhaps even
> prevalent, style).

As much as I admire FORMAT magic, I think that writing a small library
with a transparent template mechanism for these purposes would be a
better solution.

Best,

Tamas

Pascal J. Bourguignon

unread,
Feb 26, 2012, 10:31:28 AM2/26/12
to
Aleksej Saushev <as...@inbox.ru> writes:

> Marco Antoniotti <mar...@gmail.com> writes:
>
>> (defun print-person-title (fn sn in tc)
>> (let ((person (make-person :title-code tc :first-name fn
>> :initials in :surname sn)))
>> (loop for language in '(:en :fr :it)
>> as language-index from 0
>> do
>> (format t "~[~
>> ~[Mr.~;Mrs.~;Miss~;Dr.~] ~A ~A. ~A~%~;~
>> ~[M.~;Mme~;Mlle~;Dr.~] ~:@(~4@*~A~) ~2@*~A~%~;~
>> ~[Sig.~;Sig.ra~;Sig.na~;dott.~] ~@(~4@*~A~) ~2@*~A~%~:;~
>> Lup. Mann. ~@(~4@*~A~) ~2@*~A~%~
>> ~]"
>> language-index
>> (title-code person)
>> (first-name person)
>> (initials person)
>> (surname person)))))
>
> It would be interesting to see how you handle languages where there's
> either full name or initials and where titles like "doctor" come after
> surname (Russian, Ukrainian, Belarusian).

Trivially.

~[X~;Y~;Z~;~] *~A ~A. ~A ~0@*~[~;~;~;W~] ~%~;~

What's harder to do is if the language has declination affecting the
names.


> It would be interesting to see how you handle languages where surname
> goes before first name (Hungarian, Russian in another, perhaps even
> prevalent, style).

Again, trivially. That was the whole point of my message, to show how
trivial it was to do, using ~*.

~[X~;Y~;Z~;~] ~3@*~A ~1@*~A ~0@*~[~;~;~;W~] ~%~;~

Aleksej Saushev

unread,
Feb 27, 2012, 3:16:17 AM2/27/12
to
These don't work:

$ sbcl --no-userinit
* (defun print-person-title (fn sn in tc)
(loop for language in '(:en :fr :it :ru1 :ru2)
as language-index from 0
do
(format t "~[~
~[Mr.~;Mrs.~;Miss~;Dr.~] ~A ~A. ~A~%~;~
~[M.~;Mme~;Mlle~;Dr.~] ~:@(~4@*~A~) ~2@*~A~%~;~
~[Sig.~;Sig.ra~;Sig.na~;dott.~] ~@(~4@*~A~) ~2@*~A~%~:;~
~[X~;Y~;Z~;~] *~A ~A. ~A ~0@*~[~;~;~;W~] ~%~;~
~[X~;Y~;Z~;~] ~3@*~A ~1@*~A ~0@*~[~;~;~;W~] ~%~;~
Lup. Mann. ~@(~4@*~A~) ~2@*~A~%~
~]"
language-index
tc
fn
in
sn)))
* (print-person-title "Nikolaj" "Kuznecov" "Ivanovich" 0)
Mr. Nikolaj Ivanovich. Kuznecov
M. KUZNECOV Nikolaj
Sig. Kuznecov Nikolaj
X *Nikolaj Ivanovich. Kuznecov W
X Ivanovich 0
NIL

It is easy to see that it prints extraneous placeholder, space, asterisk,
and dot after father's name. In the second case the output is completely
incomprehensible. Perhaps, FORMAT isn't as powerful as you wish me to think. :)


Just for your information, here're examples of correct output:

Nikolaj Ivanovich Kuznecov
Kuznecov Nikolaj Ivanovich
Kuznecov N. I. (sorry, monospace font here)

With academic degree it should be something like

Nikolaj Ivanovich Kuznecov, d.ph.-m.n.
Kuznecov Nikolaj Ivanovich, d.ph.-m.n.
Kuznecov N. I., d.ph.-m.n.

your solution gives this:

Dr. Nikolaj Ivanovich. Kuznecov
Dr. KUZNECOV Nikolaj
dott. Kuznecov Nikolaj
*Nikolaj Ivanovich. Kuznecov W
Ivanovich 3


--
HE CE3OH...

Barry Fishman

unread,
Feb 27, 2012, 11:24:44 AM2/27/12
to
In following this discussion I thought I would reply to Aleksej Saushev
message looking to format things like:

> Kuznecov Nikolaj Ivanovich, d.ph.-m.n.
> Kuznecov N. I., d.ph.-m.n.

Not being familiar with Russian, I though he might mean something
more like

> Kuznecov Nikolaj Ivanovich, D.Ph.
> Kuznecov N. I., D.Ph.

The most difficult part seemed to be selecting between initials and
long form of names. I updated the code to the following, adding
a class definition.

--8<---------------cut here---------------start------------->8---
(defclass person ()
((title-code :initarg :title-code :accessor title-code)
(first-name :initarg :first-name :accessor first-name)
(middle-name :initarg :middle-name :accessor middle-name)
(surname :initarg :surname :accessor surname)))

(defmacro make-person (&rest rest)
`(make-instance 'person ,@rest))

(defun initial (name)
(char name 0))


(defun print-person-title (fn mn sn tc)
(let ((person (make-person :title-code tc :first-name fn
:middle-name mn :surname sn)))
;(describe person)
(loop for language in '(:en :fr :it :ru1 :ru2 :what)
as language-index from 0
do
(format t "~[~
~[Mr.~;Mrs.~;Miss~;Dr.~] ~3@*~A ~C. ~6@*~A~;~
~[M.~;Mme~;Mlle~;Dr.~] ~:@(~6@*~A~) ~3@*~A~;~
~[Sig.~;Sig.ra~;Sig.na~;Dott.~] ~@(~6@*~A~) ~3@*~A~;~
~6@*~A ~3@*~A ~5@*~A~@*~[~;~;~;, D.Ph.~]~;~
~6@*~A ~2@*~C. ~4@*~C.~@*~[~;~;~;~;, D.Ph.~]~;~
~6@*~A ~2@*~C. ~4@*~C.~@*~A~
~]~%"
language-index ; 0
(title-code person) ; 1
(initial (first-name person)) ; 2
(first-name person) ; 3
(initial (middle-name person)) ; 4
(middle-name person) ; 5
(surname person))))) ; 6


(print-person-title "Nikolaj" "Ivanovich" "Kuzenecov" 3)
--8<---------------cut here---------------end--------------->8---

Which gives the following output:

--8<---------------cut here---------------start------------->8---
Dr. Nikolaj I. Kuzenecov
Dr. KUZENECOV Nikolaj
dott. Kuzenecov Nikolaj
Kuzenecov Nikolaj Ivanovich, D.Ph.
Kuzenecov N. I., D.Ph.
Kuzenecov N. I.5
--8<---------------cut here---------------end--------------->8---

What seems to be happening is that every time I do a "~@*" it seems
to increment the value of language-index.

I did not see anything about this in the hyperspec, so I thought it was
an implementation bug, but I got the same results with Clisp, CMUCL,
SBCL, and Clozure CL.

Can someone explain what is happening?

--
Barry Fishman

Aleksej Saushev

unread,
Feb 27, 2012, 6:47:28 PM2/27/12
to
Barry Fishman <barry_...@acm.org> writes:

> In following this discussion I thought I would reply to Aleksej Saushev
> message looking to format things like:
>
>> Kuznecov Nikolaj Ivanovich, d.ph.-m.n.
>> Kuznecov N. I., d.ph.-m.n.
>
> Not being familiar with Russian, I though he might mean something
> more like
>
>> Kuznecov Nikolaj Ivanovich, D.Ph.
>> Kuznecov N. I., D.Ph.

No, I meant what I wrote. What should "D.Ph." mean in your case?
"Doctor" isn't personal name, thus it should be lowercase "d."
"D.f.-m.n." means (in a more correct romanization) "doktor fiziko-matematicheskikh
nauk," a title for contribution to physics, mathematics and related fields.
"D.f.n." would mean completely different academic title (something from humanities).

> The most difficult part seemed to be selecting between initials and
> long form of names.

Unfortunatly, no. It isn't the most difficult part.
What if Nikolaj Ivanovich is actually chemist or biologist?
The title should be "d.kh.n." or "d.b.n." then.

The problem is that output format is more complex than it can be
actually handled by FORMAT. It is easier to dispatch on language
rather than lump everything into single format string. (It is already
not easy to comprehend.)

> I updated the code to the following, adding
> a class definition.
>
> (defclass person ()
> ((title-code :initarg :title-code :accessor title-code)
> (first-name :initarg :first-name :accessor first-name)
> (middle-name :initarg :middle-name :accessor middle-name)
> (surname :initarg :surname :accessor surname)))
>
> (defmacro make-person (&rest rest)
> `(make-instance 'person ,@rest))
>
> (defun initial (name)
> (char name 0))

The rule is more complex than taking the first letter. :)
Though I agree that it is rather easy to handle.

> (defun print-person-title (fn mn sn tc)
> (let ((person (make-person :title-code tc :first-name fn
> :middle-name mn :surname sn)))
> ;(describe person)
> (loop for language in '(:en :fr :it :ru1 :ru2 :what)
> as language-index from 0
> do
> (format t "~[~
> ~[Mr.~;Mrs.~;Miss~;Dr.~] ~3@*~A ~C. ~6@*~A~;~
> ~[M.~;Mme~;Mlle~;Dr.~] ~:@(~6@*~A~) ~3@*~A~;~
> ~[Sig.~;Sig.ra~;Sig.na~;Dott.~] ~@(~6@*~A~) ~3@*~A~;~
> ~6@*~A ~3@*~A ~5@*~A~@*~[~;~;~;, D.Ph.~]~;~
> ~6@*~A ~2@*~C. ~4@*~C.~@*~[~;~;~;~;, D.Ph.~]~;~
> ~6@*~A ~2@*~C. ~4@*~C.~@*~A~
> ~]~%"
> language-index ; 0
> (title-code person) ; 1
> (initial (first-name person)) ; 2
> (first-name person) ; 3
> (initial (middle-name person)) ; 4
> (middle-name person) ; 5
> (surname person))))) ; 6

Here you pass initials and full names even if you don't actually need them
like in Western European languages. This makes format strings more complex, e.g.

~[Mr.~;Mrs.~;Miss~;Dr.~] ~A ~A. ~A~%~;~

became

~[Mr.~;Mrs.~;Miss~;Dr.~] ~3@*~A ~C. ~6@*~A~;~

And when you cram more languages into it, you may find that original
simplicity in format strings for English, French, and Italian is lost.
And so is lost simplicity of format strings for Russian, Belarusian,
and Ukrainian, if taken separatly from original set.

This brings us back to original claim:

"And format is great for localization."

Unfortunatly not. FORMAT is not great for localization.

Localization is really not that easy problem to attack it with one fixed
format string for every language. It is not easy even in such restricted
case as printing person name with title.


--
HE CE3OH...

WJ

unread,
Mar 4, 2015, 11:29:39 PM3/4/15
to
Gauche Scheme:

(define db
'((Title Home Artist "Dixie Chicks" Rating 9 Ripped #t)
(Title Fly Artist "Dixie Chicks" Rating 8 Ripped #t)
(Title Roses Artist "Kathy Mattea" Rating 7 Ripped #t)))

(define (print-db db)
(dolist (cd db)
(dolist (x (slices cd 2))
(format #t "~10a~a~%" (format "~a:" (car x)) (cadr x)))
(newline)))

Title: Home
Artist: Dixie Chicks
Rating: 9
Ripped: #t

Title: Fly
Artist: Dixie Chicks
Rating: 8
Ripped: #t

Title: Roses
Artist: Kathy Mattea
Rating: 7
Ripped: #t


0 new messages