これまででわかりにくかったところと、まだわからないところ。
わかりにくかったところ
Common Lisp勉強中に「ソースコードが読めない!」と感じた部分が多いです。
関数の定義場所
リストの先頭が関数で残りは引数。という考え方でほとんど読めるのですが、 まだ覚えきれていない間はその関数は何かわからないことが多く、いちいち悩みました。
候補にこれらが混ざっていることが多いです。
- Common Lispで規定された関数
- →clqr (Common Lisp Quick Reference)やCLHS (CLHS: Alphabetical Symbol Index (Full))で探す。
- 私はclqrをコンビニで印刷して製本したものを側に置いています。
- その資料中で事前に定義されたもの
- →忘れてる。索引があれば探す
- すぐ後で説明と共に定義される
- 悩むんじゃなかった。。。
(追記
シンボルの定義場所はslimeを使っているなら M-.を使うと処理系のソースに飛べる。
— Masatoshi SANO (@snmsts) November 24, 2016
sbcl-binでsbclを入れている場合ソースが無いので 'ros install sbcl/`ros config show sbcl-bin.version` --without-install' とかやっとくと飛べるようになるはず…
— Masatoshi SANO (@snmsts) November 24, 2016
処理系のソースにも飛べるのを知らなかった。これも活用しないと。 )
記号
私はCommon Lispのいいところの一つは「記号が少ないところ」だと思うのですが、それゆえ記号が出現すると途端に読めませんでした。 リードマクロと呼ばれるのか、まだ理解していない部分。
CLHSに記載されてました。最初にみとけばよかった。。。 c.f. CLHS: Section 2.4 Standard Macro Characters
'
= quote- 評価しない
'(a b c '(a))
=(quote (a b c (quote a)))
#'
= function#'+
=(function +)
- ググるなら sharp quote
- c.f. Common Lispにおけるlambdaのあれこれ | ありえるえりあ
#\
文字リテラル- ググるなら common lisp sharp backslash
- c.f. CLHS: Section 2.4.8.1
- その他
#
で始まるもの- CLHS: Section 2.4.8
- (こんなページがあるのに今気づいた)
- バッククォート
`
(表記上全角だけど実際は半角)、,
、,@
- まだ理解しきれていないが、クォートしたい部分と評価したい部分が混ざっている場合に使う。
- 評価しないが、部分的に評価したい。
,
をつけた部分はlistとして評価され、,@
をつけた部分はそのまま評価される。 - 展開するなら、
,
や,@
が付いていないものに'
をつけ、,
がついたものはlist
に入れられ、,@
がついたものはそのまま展開されるようなイメージ? - CLHS: Section 2.4.6 の先頭に例が載っていた。
The backquote introduces a template of a data structure to be built. For example, writing
`(cond ((numberp ,x) ,@y) (t (print ,x) ,@y))
is roughly equivalent to writing
(list 'cond (cons (list 'numberp x) y) (list* 't (list 'print x) y))
generic functions、CLOSのメソッド、アクセサ、構造体
関数だと思って探しても見つからない。 本やブログではなく既存のソースコードを読んでいるときに困った。
そのクラスで定義されたメソッドやアクセサはdefmethodやdefclassを探す必要がある。
(追記2
make-<構造体名>
これも構造体だと気づいていないと定義が見つからない。(defstruct <構造体名> ...)
を探す。
)
(追記 redd.it
masatoiさん、g000001さんにより Moptilitiesのmoptilities:direct-specializers-of
、LispWorksの機能が挙げられています。LispWorks便利だなぁ。
)
まだわからないところ
ある程度読めるようになってきて、少しずつ書こうとしているが詰まる。 詰まっている部分を整理して、自分のわからない部分を明確にして調べられるようにする。
ライブラリやパッケージの扱い
一般に公開されているライブラリを読み込んで使うには (ql:quickload :library-name)
で良いことがわかるが、
自作のパッケージを作ろうと思うと、読み込めない。
どこに何をおけば読み込めるのか。load
、require
、ql:quickload
の違いやそれぞれ参照するパスがわからない。
- ASDFはインストールの仕組みだけ?
- Quicklispでロードできるものは公開されているものだけ?
- プロジェクトローカルとユーザーローカルの違いはqlotとQuicklisp?
- Roswellで
ros install user/repo
するとql:quickload
できるのはどの仕組みから? - 一度インストールされたもの(
~/.roswell/local-packages/
内のソース)を修正しても反映されない? - ライブラリを作ろうと思うとasdファイルには何を書けば良い?
cl-project:make-project
で雛形を作った後、asdファイルの:components
にはすべてのファイルを記述する?
- asdファイルがなかったり、Quicklispに登録されていないものを使うための流儀は?
- REPLだと実行できるが、clackupコマンドで実行するとライブラリが見つからないのはなぜ
- 実行時のCWDによってライブラリが読み込めない
Node.jsとの違い
今ある程度わかっているがNode.jsなので、そこを起点に考えてしまう。
パッケージ/ライブラリのインストール
- プロジェクトローカルだと
npm install package-name
。- これは qlot
- ユーザーローカルだと
npm install -g package-name
。- これは
(ql:quickload :library-name)
- Node.jsではこれはユーザーが利用するコマンドやその拡張のインストール用であることが多い
- プロジェクトで利用するものをユーザーローカルにインストールしても通常は参照できない。
- Common Lispではユーザーローカルにインストールしたものをプロジェクトで利用することが多い印象。
- プロジェクト毎にバージョンを固定するならqlotが必要な模様
- これは
- プロジェクトローカルだと
パッケージ/ライブラリの依存関係
- Node.jsではpackage.jsonに記述するが、Common Lispでは*.asdに対応する模様。
- Node.jsでは一つのリポジトリに一つのpackage.jsonの場合が多いイメージだが、
Common Lispでは一つのリポジトリにたくさんasdファイルが存在するイメージ。
- 同じリポジトリでも内部で利用するパッケージを分割するなら asdファイルを作る?
パッケージ/ライブラリの読み込み
- npmでプロジェクトローカルにインストールしたもの
const somePackage = require('package-name');
で読み込む
- プロジェクトローカルの別の内容を読み込む時はファイルからの相対パス
const somePackage = require('./package-name');
で読み込む
- パッケージを作っている時
npm link
でカレントディレクトリの内容をユーザーローカルにリンクし、他のプロジェクトから利用できたはず
- この辺りがCommon Lispでどうするかわからない。
- npmでプロジェクトローカルにインストールしたもの