ITエンジニアのブログ

IT企業でエンジニアやってる人間の日常について

jQueryでDOMを生成する際に躓いた点

div 要素に p を5つ追加したい時に

var div = $("<div>");
var p = $("<p>");
for(var i = 0; i < 5; i++){
    div.append(p);
}

とするとうまくいきませんでした。

var div = $("<div>");
var p;
for(var i = 0; i < 5; i++){
    p = $("<p>");
    div.append(p);
}

とするとうまくいきます。二つのコードは同じ p を使いまわしているかいないかなので、参照が同じものを追加しても複製されないことが分かりました。

インライン属性の大きさ指定

span 属性の項目に大きさを付加してみました。

span.a{
    width: 100px;
    height: 100px;
}

span.b{
    width: 50px;
    height: 50px;
}

実際に

<span class="a"><span class="b"></span></span>

として配置してみましたが、どちらも 0px になり大きさが設定できていません。

原因は、 span はインライン属性の DOM であり、インライン属性は大きさを保持できないということが決められているようです。解決策としては、 display: block; を CSS に追加してブロック要素にすることです。

プログラミング言語を作る。第14回:グローバル変数

プログラミング言語の開発について考えていたのですが、関数の部分適用など、いきなり実装するには難しい概念があるので、まずはC言語に似たプログラミング言語を作って概形を把握したいと思います。今回はグローバル変数について調査していました。普段はできるだけ静的スコープ内で変数を作って解決しようという意図でプログラミングをしているので、グローバル変数についてはあまり勝手が分かっていませんでした。ここで幾つか確認したいと思います。

#include <stdio.h>

char c = 'c';
short s = 12;
int i = 100;
float f = 3.4f;
long long ll = 123ll;
double d = 12.0;

int main(void){
    printf("%c\n", c);
    printf("%d\n", s);
    printf("%i\n", i);
    printf("%f\n", f);
    printf("%lld\n", ll);
    printf("%f\n", d);
    return 0;
}
        .file	"main.c"
.globl c
	.data
	.type	c, @object
	.size	c, 1
c:
	.byte	99
.globl s
	.align 2
	.type	s, @object
	.size	s, 2
s:
	.value	12
.globl i
	.align 4
	.type	i, @object
	.size	i, 4
i:
	.long	100
.globl f
	.align 4
	.type	f, @object
	.size	f, 4
f:
	.long	1079613850
.globl ll
	.align 8
	.type	ll, @object
	.size	ll, 8
ll:
	.quad	123
.globl d
	.align 8
	.type	d, @object
	.size	d, 8
d:
	.long	0
	.long	1076363264
	.section	.rodata
.LC0:
	.string	"%c\n"
.LC1:
	.string	"%d\n"
.LC2:
	.string	"%i\n"
.LC3:
	.string	"%f\n"
.LC4:
	.string	"%lld\n"
	.text
.globl main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	movzbl	c(%rip), %eax
	movsbl	%al, %edx
	movl	$.LC0, %eax
	movl	%edx, %esi
	movq	%rax, %rdi
	movl	$0, %eax
	call	printf
	movzwl	s(%rip), %eax
	movswl	%ax, %edx
	movl	$.LC1, %eax
	movl	%edx, %esi
	movq	%rax, %rdi
	movl	$0, %eax
	call	printf
	movl	i(%rip), %edx
	movl	$.LC2, %eax
	movl	%edx, %esi
	movq	%rax, %rdi
	movl	$0, %eax
	call	printf
	movss	f(%rip), %xmm0
	unpcklps	%xmm0, %xmm0
	cvtps2pd	%xmm0, %xmm0
	movl	$.LC3, %eax
	movq	%rax, %rdi
	movl	$1, %eax
	call	printf
	movq	ll(%rip), %rdx
	movl	$.LC4, %eax
	movq	%rdx, %rsi
	movq	%rax, %rdi
	movl	$0, %eax
	call	printf
	movsd	d(%rip), %xmm0
	movl	$.LC3, %eax
	movq	%rax, %rdi
	movl	$1, %eax
	call	printf
	movl	$0, %eax
	leave
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-16)"
	.section	.note.GNU-stack,"",@progbits

align で幅を指定し、 byte, value, long, quad にて値を設定しているようです。グローバル変数の値の設定のときに、 i = 100 を i = 100 + 1 にしても GCC で動作しました。勝手に 101 に定数畳み込みで最適化されているようです。ところが、 atoi("43") のようにすると、初期化子は定数ではないとエラーが出力されました。

社会人になった

社会人になりました。エンジニアとして働きます。

これから、趣味のプログラミングや勉強に加え、音楽制作、イラスト描画に割ける時間が大幅に少なくなると思いますが、様子を見ながら頑張っていけたらと思います。

アーロンチェアを買った

ハーマンミラーという店でアーロンチェアを買いました。定価は17万円近くでしたが、中古品をリニューアルして新品の部品と入れ替えたものが11万円で提供できるとの事だったので、それにしました。とても高価な買い物で、まだ社会人になっておらず所持金が厳しいので分割で払うことにしました。

なぜアーロンチェアを買ったか。以前から、どうも自分の部屋でデスクワークが殆どできなかったのです。すぐ寝転がってしまいたくなり、10分くらいで集中力が切れたりして、全然作業が進みませんでした。それが椅子のせいだと気づくのに時間がかかりましたが、Twitterで絵や音楽を創造している人たちの作業風景を公開する流れで、誰かがアーロンチェアが多い事に気づいていましたので、なんとか自分もそこに帰結することができました。

実際座ってみて、とても快適だと感じます。今まで使っていたニトリの4000円程度の椅子とは段違いです。長時間座って作業するために、椅子はとても重要な要因だということですね。

Schemeインタプリタについての話

github.com


自身のウェブサイトで各プログラムの GitHub 及び Bitbucket のリポジトリ内でのコード記述行数を掲載しているのですが、 Scheme の記述行数がかなり少なかったので、 Scheme で何か書こうと思いました。大学の講義で Scheme による Scheme インタプリタを実装したことがあって、そのプログラムを紛失してしまっていたので、再び書き直そうと思いました。 Scheme インタプリタについては以前 Ruby でも書いたことがあります。

Scheme では read という関数を用いて S式を読み込むことが可能なので、構文解析についてはこれだけで完成してしまいます。

次は評価です。構文解析によって S式 s が与えられたとします。これが、例えば 1 や #t などのリテラルであれば、特に変更を加えること無くそのまま返り値とできます。

s がシンボルの場合を考えます。インタプリタでは環境という概念があって、環境で変数と値が束縛されています。 gosh で次のような入力

(define a 1)

を与えると、 (a, 1) という関係が環境の中に定義され、 a という変数を評価すると 1 を返すようになります。インタプリタを作成する場合、この環境を正しく実装することが重要です。

実は、インタプリタの種類によって、環境の形状も変わってきます。 GitHub 上に OCaml で実装した型推論付き ML インタプリタも公開していますが、 Scheme インタプリタとは環境の構成が変わっています。私はこの2種類の環境を知っていて、それぞれフレーム型と直線型というように勝手に名付けています。それぞれについて少し説明してみます。

まずフレーム型です。先程も言及した通り、呼び方は私が勝手に決めただけで、一般的なものではありません。このタイプは Scheme などで取られている手法ですが、インタプリタに限らない場合、 C言語Java なども同じようなものと考えても良いと思います。例が示しやすい C言語で話をしてみます。

int a = 3;
int b = 2;

int add(int x){
  return a + x;
}

このように、同じスコープに定義されている変数は、同じフレーム内に変数が束縛されています。この例だと、グローバルのスコープに対応する環境は下記のようになります。

[(a, 3), (b, 2)]

そして、 if や関数定義の中括弧の中では、さらに一つのフレームがスタックのように上に作られます。例えば、 add(5) を実行したとしましょう。 x に 5 が束縛されます。

[(x, 5)], [(a, 3), (b, 2)]

変数を参照する場合は、上のフレームから順に探索され、値を見つけます。関数適用が終わった時に、上のフレームのみ削除されます。こうすることで、他のスコープを汚すこと無く実行できます。

次に直線型について。 OCamlインタプリタなどを実行した際にこれになります。

let a = 1;;
let add x = x + a;;

上記の式を定義したとき、環境は [(add, ), (a, 1)] となっています。ここで、

let b = 3 in add b;;

を実行しても、途中経過は次のようになり、フレームなどは作られません。

[(x, 3), (b, 3), (add, <fun>), (a, 1)]

勿論、関数適用や let ... in が終われば、 x や b の束縛は消去されます。

この違いは、次のプログラムを実行するとわかりやすいかもしれません。

フレーム型 (Scheme)

(define a 7)
(define (add n) (+ n a))
(add 1)
(define a 10)
(add 1)

直線型 (OCaml)

let a = 7;;
let add n = n + a;;
add 1;;
let a = 10;;
add 1;;

Scheme では add 1 の結果が 8 から 11 になりますが、 OCaml では変更がありません。 Scheme ではフレームの最深部で a の値が変更されたため、関数適用の際にその変更が影響しますが、 OCaml では関数定義の際に環境が定まっており、直線的にそれ以前の環境を参照するために変更が影響しないのです。

環境についても色々、ということで、話を終わります。

次に s が空ではないリストの場合を考えてみましょう。

(define a 1)

こういった場合、最初に先頭のみ評価されます。環境が変に弄られていなければ、 define という syntax が環境に入っているはずなので、 define の動作をします。 define では一番上にある連想リストに変数と値の対応関係を追加します。他の syntax も同様に、環境と式を受け取って特殊な処理を行います。先頭が subroutine の場合は、引数の値を評価して、個々の処理を行います。

クロージャを考えてみましょう。

((lambda (x) (+ x 1)) 1)

ラムダ式を評価すると、クロージャが作られます。クロージャは引数 (x) と式 (+ x 1) に加えて、そのときの環境を保持します。そして、関数を適用するときに、新たなフレームを作り、環境の一番上のスコープに乗っけて式を評価します。この場合では (+ x 1) を評価するために、仮引数 x に引数 1 を束縛して新たに環境を作り、評価します。

メロディーから作るかコードから作るか

最近、頑張って作曲をしています。まだ完成した曲はありませんが。

まだ初心者なので当然ではあるのですが、音楽を作っていて、後で聞くと「全然ダメだ」って思うことが多いです。それで何回も作り直しをしています。

今までの作曲手順は次のとおりです。

  1. テーマを決める
  2. 歌詞を書く
  3. メロディーを付ける
  4. コードを乗せる

DAWCubase Pro 8 を使っていて、ピアプロ初音ミクに歌わせ、コードトラックでピアノのコードを当てるようにしています。

今まではゼロからメロディーを先に作っていましたが、初めてコードから作ってみました。今まで何故メロディーから作っていたかというと、コードを先に決めてしまうと、それに引っ張られてメロディーに制約がかかって、メロディーの音の動きが不自由な感じになってしまうと思っていたからです。頭が固い上に初心者ですので。

ところが、コードを先に書くことで、メロディーにある程度の制約がかかった結果、逆に音の動きに柔軟性が出てきたと感じました。メロディーからの作曲は上級者向けとよくインターネット上で書いてありますが、そのとおりだと思います。今までの自分は、コードからだとメロディーが不自由に、などと考えていましたが、やはり初心者のいう自由なんてたかが知れているということですね。知識の上に自由があるというのはプログラミングにおいても音楽においても同じなのでしょう。