@peccul is peccu

(love peccu '(emacs lisp cat outdoor bicycle mac linux coffee))

Common Lisp勉強中にわかりにくかったところと、まだわかっていない部分

これまででわかりにくかったところと、まだわからないところ。

  • 追記:redditTwitterにていただいた助言を追加
  • 追記2:構造体の make-* を追加

わかりにくかったところ

Common Lisp勉強中に「ソースコードが読めない!」と感じた部分が多いです。

関数の定義場所

リストの先頭が関数で残りは引数。という考え方でほとんど読めるのですが、 まだ覚えきれていない間はその関数は何かわからないことが多く、いちいち悩みました。

候補にこれらが混ざっていることが多いです。

  • Common Lispで規定された関数
  • その資料中で事前に定義されたもの
    • →忘れてる。索引があれば探す
  • すぐ後で説明と共に定義される
    • 悩むんじゃなかった。。。

(追記

処理系のソースにも飛べるのを知らなかった。これも活用しないと。 )

記号

私はCommon Lispのいいところの一つは「記号が少ないところ」だと思うのですが、それゆえ記号が出現すると途端に読めませんでした。 リードマクロと呼ばれるのか、まだ理解していない部分。

CLHSに記載されてました。最初にみとけばよかった。。。 c.f. CLHS: Section 2.4 Standard Macro Characters

  • ' = quote
    • 評価しない
    • '(a b c '(a)) = (quote (a b c (quote a)))
  • #' = function
  • #\ 文字リテラル
  • その他 # で始まるもの
  • バッククォート(表記上全角だけど実際は半角)、,,@
    • まだ理解しきれていないが、クォートしたい部分と評価したい部分が混ざっている場合に使う。
    • 評価しないが、部分的に評価したい。,をつけた部分は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) で良いことがわかるが、 自作のパッケージを作ろうと思うと、読み込めない。

どこに何をおけば読み込めるのか。loadrequireql: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');で読み込む
    • パッケージを作っている時
    • この辺りがCommon Lispでどうするかわからない。
      • ファイルからの相対パスかと思うとCWDからの相対パスだった気がする
      • REPLでのloadとros -l some.lispそれぞれ、どこで実行すれば動くか確認が必要。