Sign In/My Account | View Cart  
advertisement


Listen Print Discuss

Exegesis 7
by Damian Conway | Pages: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13

Editor's note: this document is out of date and remains here for historic interest. See Synopsis 7 for the current design information.

Thou shalt have my best gown to make thee a pair...

Wait a minute...

Where exactly did we conjure that :locale syntax from? And what, exactly, did it create? What is an "option"?

Well, we're passing :locale as an argument to form, and form's signature guarantees us that it can only accept a Str, or an Array, or a Pair as an argument. So an "option" must be one of those three types, and that funky :identifier syntax must be a constructor for the equivalent data structure.

And indeed, that's the case. An "option" is just a pair, and the funky :identifier syntax is just another way of writing a pair constructor.

The standard "option" syntax is:


    :key( "value" )

which is identical in effect to:


    key => "value"

Both specify an autoquoted key; both associate that key with a value; both evaluate to a pair object that contains the key and value. So why have a second syntax for pairs?

Because it allows us to optimize the pair constructor syntax in two different ways. The now-familiar "fat arrow" pair constructor takes a key and a value, each of which can be of any type. In contrast, the key of an "option" pair constructor can only be an identifier, which is always autoquoted...at compile-time. So, if we use the "option" syntax we're guaranteed that the key of the resulting pair is a string, that the string that contains a valid identifier, and that the compiler can check that validity before the program starts.

Moreover, whereas the "fat arrow" has only one syntax, "options" have several highly useful syntactic variations. For example, "fat arrow" pairs can be especially annoying when we want to use them to pass named boolean arguments to a subroutine. For example:


    duel( $person1, $person2, to_death=>1, no_quarter=>1, left_handed=>1, bonetti=>1, capoferro=>1 );

In contrast, "options" have a special default behaviour. If we leave off their parenthesized value entirely, the implied value is 1. So we could rewrite the preceding function call as:


    duel( $person1, $person2, :to_death, :no_quarter, :left_handed, :bonetti, :capoferro );

Better still, when we have a series of options, we don't have to put commas between them:


    duel( $person1, $person2, :to_death :no_quarter :left_handed :bonetti :capoferro );

That makes them even more concise and uncluttered, especially in use statements:


    use POSIX :errno_h :fcntl_h :time_h;

There are other handy "option" variants as well, all of which simply substitute the parentheses following their key for some other kind of bracket (and hence some other kind of value). The full list of "option"...err...options is:


      Option syntax              Is equivalent to
    ==================     =============================

    :key("some value")     key => "some value"

    :key                   key => 1

    :key{ a=>1, b=>2 }     key => { a=>1, b=>2 }

    :key{ $^arg * 2; }     key => { $^arg * 2; }

    :key[ 1, 2, 3, 4 ]     key => [ 1, 2, 3, 4 ]

    :key«eat at Joe's»     key => ["eat", "at", "Joe's"]

Despite the deliberate differences in conciseness and flexibility, we can use "options" and "fat arrows" interchangeably in almost every situation where we need to construct a pair (except, of course, where the key needs to be something other than an identifier string, in which case the "fat arrow" is the only alternative). To illustrate that interchangeability, we'll use the "option" syntax throughout most of the rest of this discussion, except where using a "fat arrow" is clearly preferable for code readability.

Meanwhile, back in the fields...


Some tender money to me...

Formatting numbers gets even trickier when those numbers represent money. But form simply lets us specify how the local currency looks – including leading, trailing, or infix currency markers; leading, trailing, or circumfix negation markers; thousands separators; etc. – and then it formats it that way. For example:


    my @amounts = (0, 1, 1.2345, 1234.56, -1234.56, 1234567.89);

    my %format = (
        "Canadian (English)"    => q/   {-$],]]],]]].[}/,
        "Canadian (French)"     => q/    {-] ]]] ]]],[ $}/,
        "Dutch"                 => q/     {],]]],]]].[-EUR}/,
        "German (pre-euro)"     => q/    {-].]]].]]],[DM}/,
        "Indian"                => q/    {-]],]],]]].[ Rs}/,
        "Norwegian"             => q/ {kr -].]]].]]],[}/,
        "Portuguese (pre-euro)" => q/    {-].]]].]]]$[ Esc}/,
        "Swiss"                 => q/{Sfr -]']]]']]].[}/,
    );

    for %format.kv -> $nationality, $layout {
        print form "$nationality:",
                   "    $layout",
                        @amounts,
                   "\n";
    }

produces:


    Swiss:
                  Sfr 0.0 
                  Sfr 1.0 
                  Sfr 1.23
              Sfr 1'234.56
             Sfr -1'234.56
          Sfr 1'234'567.89

    Canadian (French):
                      0,0 $ 
                      1,0 $ 
                      1,23 $
                  1 234,56 $
                 -1 234,56 $
              1 234 567,89 $

    Dutch:
                      0.0EUR  
                      1.0EUR  
                      1.23EUR 
                  1,234.56EUR 
                  1,234.56-EUR
              1,234,567.89EUR

    Norwegian:
                   kr 0,0 
                   kr 1,0 
                   kr 1,23
               kr 1.234,56
              kr -1.234,56
           kr 1.234.567,89

    German (pre-euro):
                      0,0DM 
                      1,0DM 
                      1,23DM
                  1.234,56DM
                 -1.234,56DM
              1.234.567,89DM

    Indian:
                      0.0 Rs 
                      1.0 Rs 
                      1.23 Rs
                  1,234.56 Rs
                 -1,234.56 Rs
              12,34,567.89 Rs

    Portuguese (pre-euro):
                      0$0 Esc 
                      1$0 Esc 
                      1$23 Esc
                  1.234$56 Esc
                 -1.234$56 Esc
              1.234.567$89 Esc

    Canadian (English):
                     $0.0 
                     $1.0 
                     $1.23
                 $1,234.56
                -$1,234.56
             $1,234,567.89

Nice, eh?


Able verbatim to rehearse...

But sometimes too nice. Sometimes all we want is an existing block of data laid out into columns – without any fancy reformatting or rejustification. For example, suppose we have an interesting string like this:


    $diagram = <<EODNA;
       G==C
         A==T
           T=A
           A=T
         T==A
       G===C
      T==A
     C=G
    TA
    AT
     A=T
      T==A
        G===C
          T==A
    EODNA

and we'd like to put beside some other text. Because it's already carefully formatted, we really don't want to interpolate it into a left-justified field:


    print form
        '{[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]}       {[[[[[[[[[[[[[[[}',
         $diatribe,                                        $diagram;

Because that would squash our lovely helix:


    Men at  some  time  are  masters  of  their       G==C             
    fates: / the fault, dear Brutus, is not  in       A==T             
    our genes, / but in ourselves, that we  are       T=A              
    underlings.  /  Brutus  and  Caesar:   what       A=T              
    should be in that 'Caesar'?  /  Why  should       T==A             
    that DNA be sequenced more  than  yours?  /       G===C            
    Extract them together, yours is as  fair  a       T==A             
    genome; / transcribe them, it  doth  become       C=G              
    mRNA as well; / recombine them,  it  is  as       TA               
    long; clone with 'em, / Brutus will start a       AT               
    twin as soon as Caesar. / Now, in the names       A=T              
    of all  the  gods  at  once,  /  upon  what       T==A             
    proteins doth our Caesar feed, / that he is       G===C            
    grown so great?                                   T==A

Nor would right-, full-, centre- or numeric- justification help in this instance. What we really need is "leave-it-the-hell-alone" justification – a field specifier that lays out the data exactly as it is, leading whitespace included.

And that's the purpose of a verbatim field. A verbatim single-line field ({'''''''''}) grabs the next line of data it's offered and inserts as much of it as will fit in the field's width, preserving whitespace "as is". Likewise a verbatim block field ({"""""""""}) grabs every line of the data it's offered and interpolates it into the text without any reformatting or justification.

And that's precisely what we needed for our diagram:


    print form
        '{[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]}       {"""""""""""""""}',
         $diatribe,                                        $diagram;

to produce:


    Men at  some  time  are  masters  of  their          G==C          
    fates: / the fault, dear Brutus, is not  in            A==T        
    our genes, / but in ourselves, that we  are              T=A       
    underlings.  /  Brutus  and  Caesar:   what              A=T       
    should be in that 'Caesar'?  /  Why  should            T==A        
    that DNA be sequenced more  than  yours?  /          G===C         
    Extract them together, yours is as  fair  a         T==A           
    genome; / transcribe them, it  doth  become        C=G             
    mRNA as well; / recombine them,  it  is  as       TA               
    long; clone with 'em, / Brutus will start a       AT               
    twin as soon as Caesar. / Now, in the names        A=T             
    of all  the  gods  at  once,  /  upon  what         T==A           
    proteins doth our Caesar feed, / that he is           G===C        
    grown so great?                                         T==A

Note that, unlike other types of fields, verbatim fields don't break and wrap their data if that data doesn't fit on a single line. Instead, they truncate each line to the appropriate field width. So a too-short verbatim field:


    print form
        '{[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]}       {""""""}',
         $diatribe,                                        $diagram;

results in gene slicing:


    Men at  some  time  are  masters  of  their          G==C 
    fates: / the fault, dear Brutus, is not  in            A==
    our genes, / but in ourselves, that we  are              T
    underlings.  /  Brutus  and  Caesar:   what              A
    should be in that 'Caesar'?  /  Why  should            T==
    that DNA be sequenced more  than  yours?  /          G===C
    Extract them together, yours is as  fair  a         T==A  
    genome; / transcribe them, it  doth  become        C=G    
    mRNA as well; / recombine them,  it  is  as       TA      
    long; clone with 'em, / Brutus will start a       AT      
    twin as soon as Caesar. / Now, in the names        A=T    
    of all  the  gods  at  once,  /  upon  what         T==A  
    proteins doth our Caesar feed, / that he is           G===
    grown so great?                                         T=

rather than teratogenesis:


    Men at  some  time  are  masters  of  their          G==C 
    fates: / the fault, dear Brutus, is not  in            A=-
    our genes, / but in ourselves, that we  are       =T      
    underlings.  /  Brutus  and  Caesar:   what              -
    should be in that 'Caesar'?  /  Why  should       T=A     
    that DNA be sequenced more  than  yours?  /              -
    Extract them together, yours is as  fair  a       A=T     
    genome; / transcribe them, it  doth  become            T=-
    mRNA as well; / recombine them,  it  is  as       =A      
    long; clone with 'em, / Brutus will start a          G===C
    twin as soon as Caesar. / Now, in the names         T==A  
    of all  the  gods  at  once,  /  upon  what        C=G    
    proteins doth our Caesar feed, / that he is       TA      
    grown so great?                                  AT      
                                                   A=T    
                                                    T==A  
                                                      G==-
                                                  =C      
                                                        T-
                                                  ==A

Pages: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13

Next Pagearrow