できる気がしてきた。

僕の興味のあることを共有します。

JavaScriptのAwaitはcall/ccだということ。

Schemeの継続について調べると、なんだか「簡単」って言いつつ難しい説明をしてる記事が多いですが、実は普段から僕達は継続を使っています。 たとえば次のコードはES7とSchemeで書かれた”Hello"と表示するプログラムです。

(define (say)
  (display (call/cc (lambda (c) (c "Hello")))))
(say)
async function say() {
  console.log(await new Promise(c => {
    c("Hello");
  }));
}
say();

どちらのcも関数です。そしてcは継続と呼ばれていて次の処理を意味しています。 しかし、JavaScriptの場合はこのcresolveなどと書いて、成功した時にreturnのように扱えるものとして紹介されていますね。

ところで、残念ながら(?)JavaScriptの継続はSchemeの継続に完全な互換性を持っていません。というものSchemeの継続は変数に保存してあとから呼び出すことが可能ですが、JavaScriptのcは変数に保存することができません。より正確言うと、変数に保存することはできますが呼び出すときにエラーを吐きます。

これが「Schemeの継続は死んだスタックを黄泉の国から引きずり出す」なんて言われている所以です。

それはさておき、JavaScriptでも継続が使われていることがわかったところで、JavaScriptの継続の使い方をSchemeでもしてみましょう。例えばJavaScriptのawaitの醍醐味といえば非同期プログラミングを同期的に書きなおす機能でしょうか?

function slowFunctionA() {
  return new Promise(c=>c("Hello,"));
}

function slowFunctionB() {
  return new Promise(c=>c("World!"));
}

async function say(){
  const a = await slowFunctionA();
  const b = await slowFunctionB();
  console.log(a + b);
}
say()
(define (slowFunctionA c) (c "Hello,"))
(define (slowFunctionA c) (c "World!"))
(define (say)
  (let ((a (call/cc slowFunctionA))
        (b (call/cc slowFunctionB)))
    (display (+ a b))))

ほかにも、JavaScriptのyieldのnextも継続と捉えることができます。

function* say(){
  const w = yield "Hello,";
  console.log(w);
}

w = say()
console.log(w.next("World"));

この場合メソッドnextが呼ばれると、yieldされた値を返し、nextの引数をwへの代入操作という継続に渡しています。では、Schemeだとどう書くのでしょうか?ぜひ、継続の理解確認のために書いてみてください。

このように、Schemeの継続は継続として勉強すると難しいですが、普段から私達は便利に継続を扱っています。継続を理解する方法として僕は、意味を理解せずに使い方を覚えていって、それらを抽象化した時に継続を理解すれば良いのではと思いました。

なぜ文芸的プログラミングなのか

OSSソフトウェアとしてソフトウェアを公開するとき、僕が一番気にするのはソースコードの読みやすさです。 どんなに優れたソフトウェアでも、開発を継続するにはソースコードが読みやすくないとモチベーションが維持できません。

読みやすさには、いろいろな観点がありますが、その一つとして僕は「どのサブルーチンをから読むべきか」を経験則として挙げます。 例えばC言語で書かれたソフトウェアのソースコードを読むとき、main関数から下る方向に読んでもどのように動作するのか全くわかりません。 なぜなら開発者自身がmain関数からプログラムを書き始めないからです。

普通プログラムを作るとき、僕達は欲しい機能に関するサブルーチンを作り、 それをまとめる形でプログラムが完成しさせていきます。 ですから、main関数から読んでもそのソフトウェアの開発者の意図というのは読み取れません。

そこで僕はプログラムを書くときに文芸的プログラミングをすることを提案します。 文芸的プログラミングというとドナルド・クヌース氏の超絶技巧を尽くした芸術的なものを想像しますが、 僕には到底無理なので以下のようにします。

  • 開発した順番・読んで欲しい順番で章立てする
  • 機能ごとに節替えする。
  • 内容は「何をしているか」ではなく「どういう理由で何をしたいか」を書く。
  • 可能であれば目次を作る。

以上を守ることで、そこそこまともな文芸的プログラミングが出来ます。

宣伝

実現するためにCommonLisp向けのシンプルなライブラリPapyrusパピルス)」を紹介します。 Papyrusは、リードマクロ上で実現されたMarkdownCommonLispの文芸的プログラミング支援ライブラリです。

リードマクロ上で実現されているため、一切のコード生成を開発者は行わなくて良くなります。 これは、他のコメントベースの文芸的プログラミングツールでも実現されていました。

しかし、それらはドキュメント生成にはコンパイルが必要でした。 Papyrusは、全体をMarkdownで書くことが可能なので、 ドキュメントをコンパイルせず、そのままでGithubなどで綺麗にレンダリングしてくれます。

文芸的プログラミングをするのは面倒だと思いがちですが、 Markdownで書きはじめることができるので気軽に始めることが出来ます。

エレガントなソースコードを書くには相当の技量が必要ですが、 解読しやすいソースコードを書くのでしたら文芸的プログラミングで解決可能です。 これを機会に、どうでしょうか?

github.com

そろそろNeoVimに移行してよいのではないだろうか?

NeoVimはVimリファクタリングし、モダンな設計に書きなおしたバージョンだ。 Github上で開発されておりコミュニティベースで開発が進められている。

Githubのグラフを見るに2014年に始まったプロジェクらしい。 僕が見つけたときには、すでにクラウドファンディングがスタートし開発が活発になっていた時だ。

github.com

当時はVimの作者であるBram Moolenaar氏が批判的なコメントをしていたり、古参Vimmer達が色々と意見をいっていたりあまり良く受け入れられていなかったような気がした。

しかし、そこから3年たった今NeoVimは開発ペースも安定し、Neo系プラグイン開発者で有名だったShougo氏もDarkpowered系アドオンを開発し始めていたりしていて、ある程度開くティブなVimmerもNeovimを使い始めているようだ。 昔々私も「Vimmerが闇堕ちした話」というイタいポエムを書いたことがあったが、Shougo氏のおかげでevilにならなくても闇堕ちできるようになってしまった。

ta2gch.hateblo.jp

NeoVimが良かったのは後方互換性を担保した点だろう。Vimの資産をそのまま使え、その上でモジュール化を達成したことの影響はとても大きいように思える。

僕が使っていて気づいたVimとNeoVimの違いをいかに書いておこく。

  • Vim8のパッチはまだ完全にNeoVimに取り込まれていないので、Vim8の非同期APIなど一部のAPIはNeoVimでは(まだ)使えない。
  • Vimはビルド時に他の言語拡張の有効化を行うが、NeoVimは起動時に自動で判定するので、pipgem拡張機能をインストールすれば自動で有効化される。
  • Vimウガンダへの寄付を募集しているが、NeoVimはしていない。
  • Vimでシェル機能を使う場合は、Vimshellが必要だが、NeoVimは標準で組み込まれているので、:terminalで起動できる。
  • 設定ファイルの場所が違う(.vimrc.config/nvim/init.vim)

NeoVimもbrewでインストールできるのでLinux(Linuxbrew)やmacOS(Homebrew)ユーザーは是非インストールしてみてほしい。

Linuxbrew が新しくなってる

久しぶりにLinuxbrewのGithubを見てみたら、 今まで使っていた linuxbrewはlinuxbrew-legacyにとなり、 新しくFormulaを管理するリポジトリbrew本体のコードを管理するリポジトリに 分割されていた。

それに加え依存するソフトウェアも随分削られて

sudo apt-get install build-essential curl git python-setuptools ruby

のみの依存関係になっていた。

では、今まで依存していたソフトウェアはどうしているのかというと、どうも bintrayで自前で事前にコンパイルしたバイナリパッケージを使っているみたいである。

curlとgitはおそらく証明書の都合で事前インストールが必要なのだろう。 しかしpython-setuptoolsがシステムに必要なのかわからない。

とりあえず、インストール時の待ち時間がbintrayにより短縮されたのは何よりである。

余談だが、どうやったらmake_jobsを設定できるのか調べてみたら、HOMEBREW_MAKE_JOBSを環境変数として設定することでできるらしい。

Non-root package manager好きとしては、Linuxbrewは今後も要注目なソフトウェアである。

linuxbrewでempty archiveなんていうエラーが出てきたら

linuxbrewを使って、早速emacsをインストールしようとウキウキしていたら、

==> Installing emacs
==> Downloading http://ftpmirror.gnu.org/emacs/emacs-24.5.tar.xz
==> Downloading from http://mirror.tochlab.net/pub/gnu/emacs/emacs-24.5.tar.xz
######################################################################## 100,0%

Error: Empty archive

となってしまい、うまくインストールできなかった。 これは、どうやら、Githubのissueに上がっているように、 アーカイバであるxzのバージョンが腐っているときに起きる現象らしい。

なので、brewを使ってxzのバージョンアップを行う。

$ brew reinstall xz

これでemacsが使える。めでたし。

Ciderモードが新しくなってる。

普段何気なく、leiningenにnREPLの設定を書き加えていたけれど、 Githubを見たらnREPLの設定を書く必要がなくなっていた。

これからは、

(package-install 'cider)

だけで良いみたいだ。あとはcider-jack-inをするだけ。 簡単にclojureで開発できるようになってるのね。 すごいなぁ。 slimeは未だに色々と設定を書く必要があったりしていて、 やはり、開発環境の充実度が ClojureとCommonLispを分けた?決定的な違いなのかなぁとおもったりしました。

Dropboxに音楽をバックアップしたいんだけど違法なの?

Dropboxで音楽をアップロードするのは、適法なのか違法なのか これについて、MYUTA事件を参考に違法とする判断を書いているブログがある。 しかし、調べてみるとDropboxで音楽をバックアップ目的で利用することについて Dropboxを運営する会社もユーザも適法っぽいことがわかった。

根拠①

MYUTA事件の判例では、音楽ファイルの取り扱いについて行為主体が誰なのかが争点となったわけだが、 MYUTAの運営会社が行為主体として認定されたのは、「音楽ファイルを変換して送信する」というのがサービスの 一貫として認定され、また、それをMYUTA運営会社からみて不特定のユーザに送信していたと判断されたからであった。

つまり、「送信する」ところまでがメインサービスとしてしていたことで行為主体と認定されていたと読むことができる。

しかし、Dropboxでは例えばスマートフォン端末向けのアプリ等では自動同期機能はユーザによって意図的に 指定することでのみ可能になっているなど、送信するというところまでがメインサービスなのではなく、 クラウド上にバックアップを上げて保存しておくことがメインサービスになっている点で、ユーザへの送信は ユーザが行為主体となっていると判断できそうだという点でMYUTA運営会社とは決定的に違うということ。

根拠②

文化審議会著作権分科会著作物等の適切な保護と利用・流通に関する小委員会クラウドサービス等と著作権に関する報告書の19ページ整備制度の必要性の第一段落において

以上のように、タイプ2の枠内で行われる利用行為については,基本的には,利用行為主体は利用者であり, 当該利用者が行う著作物の複製行為は,私的使用目的の複製(第30条第1項)であると整理することができ, 権利者の許諾を得ることは特段不要であるとの意見で一致した。

と書かれており、文中のタイプ2とは、Dropboxのような個人がクラウド上にファイルをアップロードして個人が受信するサービスのことである。

Dropboxへアップロードする行為は技術的保護のない場合(例えば流通している多くのCDなど)を複製するのと同じ私的使用目的の複製と認定されそうだということ。

※一方で、同報告書では、

ただし,個々のサービスにおける利用行為主体の判断を含め, 私的使用目的の複製と判断されるか否かについては,当該サービスに含まれる全ての機能及び提供態様等を全体としてみた上で, 個別の事案ごとの事実認定に基づいて総合的に判断されるものと解される

としており必ずしも私的使用目的の複製認定されるか、また行為主体がユーザー側にあると判断されるかは、司法の判断次第であることを注意したい。

まとめ

少なくともMYUTA事件について言及している各所のブログ等について言えば、MYUTA事件で違法とされたのはMYUTA運営会社の行為についてでありユーザーについて言及しているわけではないということ。

また、Dropbox社が日本において適法なサービスなのかどうかは、根拠①からおそらく適法そうだということ。

Dropboxのユーザーは根拠②からおそらく適法そうだということ。

ただし、根拠②で引用した報告書には、こういったことも書かれていた

なお,タイプ2のロッカー型クラウドサービスに付加された共有機能を使って,利用者がコンテンツを個人的に 又は家庭内その他これに準ずる限られた範囲内を超えて共有する場合は,私的使用目的の複製とはいえず, 権利者の許諾を得ない限り著作権侵害となる

したがって、当たり前だが、Dropboxに権利者の許諾を得ない電子データをアップロードし、かつブログ等で共有リンクを公開するのは著作権侵害となる。

以上より、Dropboxに音楽をアップロードし、バックアップを取ることはおそらく大丈夫そうだということを結論とします。

最後に、自身の保身のために言わせていただきますと、結論は個人の見解であり、必ずしも正しいとは言えませんので、 利用にあたってはご自身で判断なさってください。

参考文献