(-> % read write unlearn)

My writings on this area are my own delusion

Ad Network(アドネットワーク)とAd Exchange(アドエクスチェンジ)

しばらくインターネット広告業界を離れていたので、色々基本的な概念がおぼろげになってしまいました。 アドネットワークとアドエクスチェンジってどっちがどんなだっけ?というやつです。言葉感が似ているので混ざりやすいんじゃないでしょうか。

Ad Netework(アドネットワーク)

複数の小規模媒体を束ねて1つの媒体のように扱えるようにする、擬似巨大媒体
農家と農協に農協に例えてみます。

  1. 個人経営農家(小規模媒体)は、作った作物(広告枠)を食べてくれる人(出稿してくれる企業=広告主)に販売したい。しかし、彼らが自分で営業活動をしてお客さん(広告主)を見つけてきて作物(広告枠)を販売するとしたら、それは非常にコストがかかります。というか多くの個人経営農家(小規模媒体)には事実上それは不可能です。*1
  2. そのため、ほげほげ農業協同組合(アドネットワーク)が、彼らの作物(広告枠)を束ねて、まとめてたくさんのお客さんに売ってくれます。
  3. ほげほげ農協(アドネットワーク)は、組合費や売上に対する手数料を徴収し、自身の財源とします。

Ad Exchange(アドエクスチェンジ)

アドネットワークの数が増えてくると、複数のアドネットワークへの入稿などの、広告主側の管理コストが非常に大きくなってきます。 そこで、様々なアドネットワークに統一的かつ柔軟に入稿/配信できる仕組みを作ろうということになりました。 この仕組みや取引市場自体をアドエクスチェンジと呼びます。

アドネットワークとアドエクスチェンジの違い

そもそも、各用語が扱っているレイヤーが全然違います。アドネットワークというのは単なる(擬似)媒体であり、広告市場のプレイヤーの1つの分類なのに対して、 アドエクスチェンジとは、媒体でも、広告主でも、まして代理店でもないです。アドエクスチェンジとは、取引市場や取引形態自体を指す用語です。
アドネットワークは媒体の一種、アドエクスチェンジは取引市場・取引形態を指す言葉。これを覚えておけば、きっとごっちゃにならずに覚えておけるはず!

*1:地産地消が回るコミュニティが全く存在しないわけではないです。またインターネットの登場によって、農家の販売チャネルの事情はだいぶ変わってきている(変わっていく)と思われます。

def と Symbol と Var の話 3 :値の変更

  1. def と Symbol と Var の話
  2. def と Symbol と Var の話 2:なぜ Symbol と Var が独立して存在するのか
  3. def と Symbol と Var の話 3 :値の変更(この記事)

前回の続きです。

defは、Symbol --> Var --> Valueという数珠つなぎを構成します。 なので、その値(というか評価結果)を変更する方法もいくつかに分けて考えられるのではないかと思います。

  1. Valueオブジェクト自体の中身を変更する。
  2. Var --> Valueの束縛を変更する。
  3. Symbol --> Varの対応を変更する。

上記の視点でシンボルの評価結果を変更する方法を調べて整理してみました。

以下の記事を参考にしました。

1. オブジェクト自体を変更する

                         ここを変更
                          |
                          V
[Symbol] --> [Var] --> [Value]

上記の図のValueのオブジェクトが mutable (可変)であれば、単にそのフィールドを変更するだけです。簡単です。 例として、上記のValueとしてjava.util.Dateオブジェクトを使用します。*1

まず、defしてVarなどを作成します。

user=> (def date (java.util.Date.))
#'user/date

user=> date
#inst "2016-08-29T05:13:40.976-00:00"
[Symbol] --> [Var] --> [Value]
 'date                  Date("2016-08-29T13:13:40.976-00:00")

続いて bind 先のオブジェクト自体の内容を変更します。ここでは、Date#setTime(long)を使用しています。

user=> (.setTime date 0)
nil
user=> date
#inst "1970-01-01T00:00:00.000-00:00"
[Symbol] --> [Var] --> [Value]
 'date                  Date("1970-01-01T00:00:00.000-00:00")

ほぼ、Javaの世界だけの話ですね。

2. Varが何を束縛(bind)しているかを変更する

                   ここを変更
                    |
                    V
[Symbol] --> [Var] --> [Value]
 'date                  Date("1970-01-01T00:00:00.000-00:00")

Varの束縛はalter-var-rootで変更できます。第一引数に対象のVar、第二引数にどう変更するかの関数を渡します。

user=> (alter-var-root #'user/date (fn [d] (.getTime d)))
0

user=> date
0
[Symbol] --+    [Var] --> [Value]
 'date     |               Date("1970-01-01T00:00:00.000-00:00")
           |
           +--> [Var] --> [Value]
                           Long(0)

#'user/date(fn [d] (.getTime d))という匿名関数で変更しました。関数の引数のdには変更前のVarの束縛対象、つまりDateオブジェクトが渡されます。受け取ったDateオブジェクトから.getTimeした値が返り値となるので、0というLongの値に変更されています。

また、alter-var-root以外にもVarの束縛を変更する方法があります。 既に intern されたSymbolを指定してdefすると、既存のVarが再利用され束縛だけが変更されます。

user=>  (def date 123)
#'user/date

user=> date
123
[Symbol] --+
 'date     |
           |
           +    [Var] --> [Value]
           |               Long(0)
           |
           +--> [Var] --> [Value]
                           Long(123)

自分でVarを変更する機会に出くわしたことがないので、実際に使ったことがないですが、 「alter-var-rootによる変更はアトミックですがdefによる変更はアトミックではない」という注意点があるようです。

3. SymbolがどのVarを拘禁(intern)しているかを変更する

         ここを変更
          |
          V
[Symbol] --> [Var] --> [Value]
 'date                  Long(123)

intern関数を使うと、SymbolVarの intern 関係を変更することができます。

user=> (intern 'user 'date "foo")
#'user/date

user=> date
"foo"
[Symbol] --+    [Var] --> [Value]
 'date     |               Long(123)
           |
           +--> [Var] --> [Value]
                           String("foo")

'dateSymbolが"foo"文字列オブジェクトを束縛した新しいVarを intern するように変更されました。

intern関数は、新しいオブジェクトを指定すると新しいVarを作成して intern しますが、既存のVarを指定するとそのVarを利用するため特に新しいVarが作成されることはありません。

user=> (intern 'user 'date #'help)
#'user/date

user=> (date)
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

nil
[Symbol] --+
 'date     |
           |
           +    [Var] --> [Value]
           |               String("foo")
           |
           +--> [Var] --> [Value]
                #'help

'dateSymbolの intern 先を help フォームに付け替えたので、dateで help フォームが実行されるようになりました。

まとめ

defで作成したSymbolに対応する内容を変更する方法を調べました。

  1. bind(束縛)されているオブジェクトの内容自体を変更する。*2
  2. alter-var-rootを用いて bind を変更する。変更はアトミック。
    変更は関数で指定し、変更前の値に応じたロジックを渡すことが可能。
  3. defを用いて bind を変更する。変更はアトミックではない。
  4. internを用いて intern を変更する。

*1:これまでは例として String オブジェクトを使ってきましたが、 Java の Stringは immutable なので今回は例としてふさわしくないです。

*2:文字列などのようにいミュータブルなオブジェクトを bind している場合は不可能

def と Symbol と Var の話 2:なぜ Symbol と Var が独立して存在するのか

  1. def と Symbol と Var の話
  2. def と Symbol と Var の話 2:なぜ Symbol と Var が独立して存在するのか(この記事)
  3. def と Symbol と Var の話 3 :値の変更

前回のdef と Symbol と Var の話の続きです。

VarSymbolの役割、defにおける挙動はなんとなく分かってきました。 では、なぜそんなややこしい*1設計になっているのでしょうか。 Javaとかには「変数名」みたいな型はないですよね。 リフレクションするときも文字列でフィールド名やメソッド名を指定します。

当然Clojureもいたずらに複雑にしたいわけではなくて、ちゃんと目的と意味があります。

lisp - Why does Clojure distinguish between symbols and vars? - Stack Overflowより、回答者levandさんのなぜClojureがSymbolやVarといった概念を導入しているのかについての説明がとても丁寧で詳しかったです。ちょっと長いですが「But why?」以降を引用します。

So why this extra concept of names as distinct from variables, rather than conflating the two as most languages do?

For one thing, not all symbols are bound to vars. In local contexts, such as function arguments or let bindings, the value referred to by a symbol in your code isn't actually a var at all - it's just a local binding that will be optimized away and transformed to raw bytecode when it hits the compiler.

Most importantly, though, it's part of Clojure's "code is data" philosophy. The line of code (def x 1) isn't just an expression, it's also data, specifically a list consisting of the values def, x, and 1. This is very important, particularly for macros, which manipulate code as data.

But if (def x 1) is a list, than what are the values in the list? And particularly, what are the types of those values? Obviously 1 is a number. But what about def and x? What is their type, when I'm manipulating them as data? The answer, of course, symbols.

And that is the main reason symbols are a distinct entity in Clojure. In some contexts, such as macros, you want to take names and manipulate them, divorced from any particular meaning or binding granted by the runtime or the compiler. And the names must be some sort of thing, and the sort of thing they are is symbols.

一応、訳してみたんですが、色々間違ってそうです。。最後の1文とか特によく分からなかったです。

いったいなぜ他の多くの言語がしているように2つの概念をまとめておくのではなく、「変数」とは区別して「名前」という余分な概念を導入したのか。

1つの理由として、全ての symbol が必ずしも var に束縛されるわけではない、ということがある。関数の引数や let 束縛のようなローカル・コンテキストにおいては、値はコード内の symbol によって参照され、参照されるのは var ではない。つまり、この場合の参照は単なるローカルの束縛なので、これらはコンパイル時に最適化され生のバイトコードに変換される。

最も重要なことだが、この設計・概念は「コードはデータである」というClojureの哲学を構成しているのだ。(def x 1)という1行のコードは、単なる式というだけではない。(def x 1)、はデータ - もっと言うならdef, xそして1からなるリストなのだ。これはとても重要なことだ。とりわけ、コードをデータとして扱い操作するマクロにとってはなおさら。

しかし、もし(def x 1)がリストだとしたら、リスト内のそれぞれの値はいったい何なのだろうか。もっと言うと、このリストのそれぞれの値の型は何になるのだろうか。3つのうち1の型は明らかに数値である。しかし、defxどうだろうか。このdefxをデータとして操作しているとき、それらの型は何になるのだろう。もちろん、この答えこそが symbol だ。

以上が、Clojureにおいて symbol が独立したエンティティであることの主な理由である。マクロのようなコンテキストでは、コンパイル時や実行時に付与される特定の意味や束縛とは分離して、それらの名前を取得し操作したい。そしてそのためには、それら名前はなんらかの「もの」の一種でなければならず、それが symbol だ。


一言で言うと、マクロで名前(変数名)を操作したいからそのためには名前もオブジェクトじゃないといけないね、ということみたいです。こういうことを知っていると、メタプログラミングをやるときの助けになってくれそうですね。

letや関数の仮引数がvarを使わないっていうのは本当なんでしょうか。感覚的には、Javaのローカル変数みたいな扱いだからなんとなくしっくりきます。 あと、そうだとして、どうしてそれが「変数名」にSymbolオブジェクトを導入した理由になるのかいまいちよく分かりません。。 そもそもちゃんと読めているのか不安。。

*1:と自分は思った