local-time:todayとlocal-time:now

The local-time Manual

SQLを扱っていると日付を指定する事が往々にある。 Common Lispからそういうコードのユニットテストを行う場合local-timeライブラリを使っている。

が、このライブラリにある関数todayと関数nowは両方ともtimestampオブジェクトを返すがタイムゾーンが違っていて、関数todayはUTCで返し、関数nowはJSTで返る。(手元の環境では) timestampオブジェクトのままなら問題ないんだろうけど、SQLに日付を埋め込むために年月日の文字列に変換して使っていると、日本時間の0時から9時までは文字列は一致しなくなる。

そして、昼間はローカルで動いてたしCIのログもSUCCESSだから何かここ数時間でローカル環境を壊したはず、という可能性を考えて深夜に色々調査するも見つからず。。。

ちなみにそのユニットテストを通すだけなら、

(setf local-time:*default-timezone* local-time:+utc-zone+)

とかどこかでやって両方共UTCにしてしまえば通る。 たまたま0時を跨ぐとやっぱり失敗する分けだがそこは気にしないとして、どうするのが正しいか。

C や C++ から Common Lisp に移って (2015年9月版)

なんか細々と思ったこととか

Emacs

EmacsCommon Lispを扱う場合にSlimeを使っているが、Slime以外にもプラグインは存在するため、Web上で見つけたEmacsCommon Lisp情報がそのまま利用できるのか、Slime向けに別の方法があるのか判断を要する。

デバッガ

Common Lispは規格としてデバッガを持っている。 処理系付属のデバッガ以外にもEmacsプラグインであるSLIMEに、似て非なる独自のデバッガがある。 SLIMEのデバッガは単なる処理系付属のデバッガ出力をそのまま表示しているだけでなく、機能拡張が色々されているので便利。

パッケージのパラメータ変更

Common Lispではsetfが変数への代入に相当するが、各種パッケージのパラメータ変更にこれを使い、グローバル変数への代入する(ように表面上見える)。 コワイ

(setf prove:*default-reporter* :dot)

実際には何らかの関数呼び出しが裏に入ってたりするので、見た目からは単純な代入なのかはよく分からない。

C や C++ から Common Lisp に移って (2015年7月版)

C や C++ から Common Lisp の世界に移って、 もちろん根本的に違う機能も多いが、 似ている部分もありつつ表面的な表記の違いで混乱する事もある。 後になると、慣れてしまって思い出せない気がするので今のうちに書いておく。 用語はかなり C や C++ よりで Common Lisp 的に間違ってる可能性が大きい。

インデント

一般にコードは構造に合わせてインデントを行う。 例えば C のスタイルでありがちなのは、 インデントはブロックの深さに合わせて4つずつ規則的にインデントする。 たまに引数の多い関数とかは引数毎に改行され関数引数の開始位置に合わせていたりして、4インデントが破られる。

    int variable0 = 0;
    int variable1 = 1;
    printf("%d\n", variable0);
    printf("%d\n", variable1);

Common Lisp でも様々なコーディングスタイルがあると思うが何となく Emacs の SLIME を使うと、 基本は 2 スペースのインデントが行われるが、 C の関数引数の改行のような何らかの構造の先頭に揃えられる事が非常に多い。 このなんらかの構造の先頭はカッコやキーワードやユーザーの定義した名称など様々で、 インデント幅もそれに合わせたサイズになり2スペースという規則は破られる。(SLIME が勝手にやってくれる)

(let ((variable0 0)
      (variable1 1))    ; 2スペースじゃない
  (print variable0)
  (print variable1))

よく古典的にアレなLispのアレで「カッコガー」とかあるが、 規則正しく 4 スペースの世界とかから移り住んで来ると、 こっちの方が大きく違和感があるのではないだろうか?

別にそれはそれで規則性があるので、 すぐになれてしまうが。

識別子名

CやC++の場合、 識別子として大文字と小文字は区別され、 upper camel case派とlower camel case派とsnake case派等がある。 でもなんかその昔は C で camel case 見なかった気がするが気のせいか?

Common Lispの場合、 識別子として大文字と小文字は区別がなく、 慣習的に小文字とハイフンで書く。(本当はその他記号とか数字とかもある) 慣習的にシステム側の出力は大文字で表示される。

構造体のアクセス

C/C++ の場合には、構造体のアクセスにオブジェクト名とメンバ変数名でアクセきる。 (コード例は実行不可能だし、不定値見にいったり、大分よろしくないが)

struct A
{
    int member;
};

A object;
object.member;

Common Lisp の場合には、make-構造体名のコンストラクタや、構造体名-スロット名のアクセサが自動で定義される。 アクセサにも構造体名がくっついてくるの、何か冗長な感じがする。

(defstruct structure-name
  (member 0))
(defvar *object*)
(let ((*object* (make-structure-name)))
  (structure-name-member *object*))

パッケージシステム

C は多分ない。 C++名前空間がある。

Common Lisp はパッケージシステムを持っているが、 シンボルがよく分からないのでパッケージもよく分からない。

フィックスターズを退社してサムライトに入社

フィックスターズ退社

株式会社フィックスターズを退社しました。理由はお察し下さい。

この会社では Cell/B.E. とか CUDA とか OpenCL とか AVX とか、主に特定プロセサ向けにポーティングしていた。

まわりは割と Windows アプリ作ってたりとかが多くて、プロファイラ見ながらアセンブラ眺めながらの仕事してる人は少数だったので、いい位置にいれた気がする。

自分もずっとそんな仕事だけだったわけではないが、一年中プロセッサの命令パイプライン埋める仕事とかなかなか良い経験だった。

サムライト入社

サムライト株式会社に入社しました。

この会社は Web 広告を扱うところで社員の多数はライターとか編集者とか (らしい、詳細はよく知らない) で、少数のプログラマが自社開発のシステムを Common Lisp で書いている。

転職活動自体は漠然と "もっと高級な言語をやりたい" で始めているけど、

  • 知人が実践 Common Lisp の翻訳者だったので読んだ
  • 知人が On Lispの翻訳者だったので読んだけど途中で挫折した
  • cl-cuda に感銘を受けた

とか興味があって、最終的には "Common Lisp やりたい" でサムライトに決めた。

入ってみて、求人タイトルにあった "まだ出社してるの?" というのは本当で、現在この会社のプログラマはリモートワークが認められてる。通常のやり取りは Slack や GitHub の Issue で、週一のミーティングも Hangouts なので、本当にプログラマと直接会う事が少ない。

出社しないと聞くと、チームとして仕事出来ないのでは?という疑問を抱く人もいて質問されるけど、今時、離れていてもやり取り出来るし、むしろ情報共有には積極的、なんだと思う。

この会社で必要となる技術と私の出来ない技術を比較してみると、

とか列挙するほどに何にも出来ない事がよく分かる。本当に大丈夫なのか?と思いながらも、今ではまわりの人に教えてもらいながら Common Lisp とか React.js とか書いている。

そんな訳で、職業 Common Lisper になりました。

C とはおさらばだ!!