Island Life

< らむ太と変身 | 仕事でLispを使うこと >

2010/02/11

文字列リテラルの連結

Rubyって文字リテラルを二つ連続で書くと連結されるの? 知らんかった。おかげでバグの理由がわからず悩んだよ。 ["hoge" "fuga"] => ["hogefuga"]
@emeitch C/C++もそうですね
@fistfvck なんと。これは誰にとって嬉しい仕様なんですかね?
文字リテラル連結はpythonでもできる。perlやjavascript(spidermonkey)ではできなかった。ほとんどではないけど、いくつかの言語処理系ではできるので、それなりに一般的な文法なんだなぁ。
あ、scheme(gauche)でも当然できなかったよ。まぁ、Lisp系言語でやられたら困るんだけど。

いくつかメリットを考えてみた。

  1. 文字列リテラル中に(無視される)改行+インデントが自由に入れられない言語では、長ーい リテラルを書こうとするとソースの横幅が伸びちゃう。ソースを80カラムに 納めたくて、かつ実行時に文字列連結をやりたくない場合に、 リテラル連結があれば自由に改行してかつインデントを揃えることができる。
    const char *long_string =
        "Lorem ipsum dolor sit amet, consectetur adipisicing "
        "elit, sed do eiusmod tempor incididunt ut labore "
        "et dolore magna aliqua. Ut enim ad minim veniam, "
        "quis nostrud exercitation ullamco laboris nisi ut "
        "aliquip ex ea commodo consequat.";
    
    (Cで'\'を入れてつなげた場合、2行目以降がインデントできない (空白文字がリテラルに 入っちゃう)。
  2. マクロが貧弱で、マクロ内で文字列連結処理ができない場合。
    #define DEFGREETING(var) \
      const char *var = "Hello, " #var "."
    
    DEFGREETING(Shiro);
    
  3. もともと、連接する式が文字列の連結演算ってセマンティクスになってる場合 (そういう言語があった気がするけど忘れちゃった。) リテラルでなくても文字列を生成する式を並べておけば、実行時に連結される。 たまたまそれが全部リテラルであった場合は、 最適化として実行前に連結されるってだけ。

第一点について。 Schemeの場合、無視される改行+インデントはR6RSで書けるようになった (Gaucheも対応済)。

(define *long-string*
    "Lorem ipsum dolor sit amet, consectetur adipisicing \
     elit, sed do eiusmod tempor incididunt ut labore \
     et dolore magna aliqua. Ut enim ad minim veniam, \
     quis nostrud exercitation ullamco laboris nisi ut \
     aliquip ex ea commodo consequat.")

CommonLispの場合、案外文字列リテラルの機能は貧弱なんだけど、 format使うと無視される改行+インデントを埋め込める。まともな処理系なら これは単なるリテラルに展開されるはず。

(defparameter *long-string*
  (format nil
          "Lorem ipsum dolor sit amet, consectetur adipisicing ~
           elit, sed do eiusmod tempor incididunt ut labore ~
           et dolore magna aliqua. Ut enim ad minim veniam, ~
           quis nostrud exercitation ullamco laboris nisi ut ~
           aliquip ex ea commodo consequat."))

ただこのCLの方法は、このformatフォームを別のリテラル (quoteされた リスト内とか)に自由に入れられないという欠点がある。`(... ,(format ...) ...) とかすればできなくはないけれど、透明でないのがいやな感じ。 マクロを利用してリテラル同士をくっつけるという解も同じ欠点がある。 (透明でない、とは、それまで単なるクオートされたリテラルだった 構造の一部をこの形式に置き換えた時に、その場所のローカルな変更だけでなく リテラルの外側にあるクオートも変更しないとだめ、ということ)。

第二点についてはLisp/Schemeではマクロ展開時に好きなだけ 文字列連結できるので問題ではない。

第三点については、Lisp/Schemeの文法と両立しない。

なのでLisp/Schemeに取り込むメリットはないけれど、言語の機能によっては メリットがあるだろう、と思う。実際C/C++では自分もよく利用するし。

Tag: Programming

Past comment(s)

emeitch (2010/02/12 07:19:03):

丁寧な回答をいただき恐縮です。 1. の長いリテラルは気づきませんでした。'\'は使ってましたが、たしかにインデントの問題がありますね。 しかし、["hoge", "fuga"]のカンマを入れ忘れちゃった場合、コンパイルエラーにもならないので、個人的には困りました...。

shiro (2010/02/13 09:24:45):

カンマを入れ忘れて悩むとは、Lisp脳がかなり進行していますね。

ishi (2010/02/15 03:24:10):

>もともと、連接する式が文字列の連結演算って >セマンティクスになってる場合 >(そういう言語があった気がするけど忘れちゃった。) snobol とか awk とか?

shiro (2010/02/15 06:49:22):

そうそう、awkがそうでしたね。snobolは使ったこと無かったです。

Post a comment

Name: