cargo installに失敗する

久しぶりにAtCoderに復帰しようとこのサイトを参考にしつつcargo-generateをinstallしようとしたら以下のエラーで失敗:

error: linking with `cc` failed: exit code: 1
...
= note: Undefined symbols for architecture x86_64:
"_RSA_get0_factors", referenced from:
_gen_publickey_from_rsa_openssh_priv_data in liblibssh2_sys-473c486114843bbe.rlib(openssl.o)
...

Macのアップデート後に利用しているopensslのバージョンがcargo-generateで利用できないようなので、明示的に古いバージョンを指定してコンパイルすることで回避:

$ OPENSSL_LIB_DIR=/usr/local/Cellar/openssl@1.1/1.1.1g/lib OPENSSL_INCLUDE_DIR=/usr/local/Cellar/openssl@1.1/1.1.1g/include cargo install cargo-generate
...
Compiling cargo-generate v0.5.1
Finished release [optimized] target(s) in 3m 16s

funcall vs apply

funcall と apply は両方とも第一引数に指定された関数を残りの引数に対して実行するのに使用できます。 基本的に、引数がリストではない場合はfuncallを使用し、引数がリストの場合はapplyを使用します。 ちなみにapplyは最後の引数がリストであれば、その他はリストでなくても実行できます。

参考

CLHS: Function FUNCALL
CLHS: Function APPLY
Common LISP Hints: Funcall, Apply, and Mapcar
common lisp - When do you use "apply" and when "funcall"? - Stack Overflow

極限までシンプルなREPL

REPL (Read-Eval-Print-Loop)は文字通り read、eval、print、loop関数を使用して実装sすることがします。
まずは最もシンプルな形式から。 read関数で読み取った入力をeval関数で実行し、print関数で出力しています。
現在のREPLでは、どこからREPLが開始されているのかが分かりづらいので、プロンプトを出力するようにします。 時間ができたらエラーハンドリングなども実装する予定。

参考

CLiki: REPL

prin1、princ、print の違いについて

Common Lisp には出力に使用される関数が複数存在します。今回はそれぞれの個性について自分なりに調べた結果を書いていきます。

  1. prin1
    read 関数に使用しやすいフォーマットとは、上記のように文字列を出力することです。人が読みやすいフォーマットで出力するには次の princ 関数を使用します。
  2. princ
    princ 関数は人の読みやすい形式で表示します。読みやすい形式とは、#\newline、#\space、#\tabなどのエスケープ文字を解釈して表示することです。 prin1 関数とは違い、princでは#\spaceが" "と解釈されてます。
  3. print
    print 関数は prin1 関数の出力の最初に改行を加えて、最後にスペースを加えたものです。

上記の関数は全て write 関数を使用してオブジェクトをストリームに書き込んでいます。 キーワードパラメータを使用することで prin1、princ、printを再現することが可能できます。

参考
CLHS: Function WRITE, PRIN1, PRINT, PPRINT...
lisp - What's the difference between write, print, pprint, princ, and prin1? - Stack Overflow

リスト内を検索する

Common Lispにはエレメントがリストに含まれているかを検索する関数が複数存在します。今回はそれぞれの違いについて自分なりに解説していきます。

  1. find
    find 関数は第一引数が第二引数のリストに含まれている場合、第一引数を返します。第一引数が第二引数のリストに存在しない場合は nil を返します。 デフォルトでは比較に eql を使用しているため、文字列や cons セルを比較する場合は、:testパラメータに equal を指定します。 find 関数の問題点としては、リストに nil が含まれているかを検索すると、含まれていても nil が返ってきてしまうことです。 上記の問題については、次に紹介するmember関数を使用することで解決します。
  2. member
    member 関数は第一引数が第二引数のリストに含まれている場合、それ以降の内容をリストにして返します。第一引数が第二引数のリストに存在しない場合は find と同じように nil を返します。
  3. position
    position 関数は第一引数が第二引数のリストに含まれている場合、そのインデックスを返します。第一引数が第二引数のリストに存在しない場合は find と同じように nil を返します。 nilを検索した際にも、存在する場合はインデックスを返すので、member のように nil がリストに含まれているかを検索できます。

参考
CLHS: Function FIND, FIND-IF, FIND-IF-NOT
CLHS: Function POSITION, POSITION-IF, POSITION-IF-NOT
CLHS: Function MEMBER, MEMBER-IF, MEMBER-IF-NOT
Check if item is in a list (Lisp) - Stack Overflow

eq、eql、equal、equalpの違いについて

今回は Common Lisp の eq、eql、equal、equalpの違いについて書いていきます。

  1. eq

    eq は 第一引数と第二引数が同じオブジェクトの場合、true を返します。 eq は主にシンボル同士を比較する場合に使用します。

  2. eql

    eql は eq が true を返す場合と、数字とcharacterの比較も行うことができます。 eq と違い、数字同士の比較と文字同士の比較が true を返しています。

  3. equal

    equal はオブジェクトのストラクチャが同一の場合、true を返します。基本的には print で同じ値が出力される場合に true が返ります。 equal はシンボル以外を比較する際に使用します。eq や eql と違い、文字列やコンスセルの比較でも true を返しています。シンボル同士を比較する場合は eq のほうが性能が良いです。

  4. equalp

    equalp は equal が true を返します。equal と違う部分は:

    1. 数字のデータ型を区別しない。
    2. 大文字小文字を区別しない。

    の二点です。

参考
CLHS: Function EQ
CLHS: Function EQL
CLHS: Function EQUAL
CLHS: Function EQUALP
syntax - What's the difference between eq, eql, equal and equalp, in Common Lisp? - Stack Overflow

mapcar, mapcan, mapcの違いについて

Common Lispにはリストのエレメントに関数をマッピングする関数が複数存在する。 今回はその中でもよく使う三つの関数 mapcar、mapc、mapcan の違いについて解説していきます。

  1. mapcar

    mapcarは第一引数の関数を第二引数以降のリストに適用することができます。 上記の例では数字のリストを二乗しています。戻り値としてラムダ関数を適用したリストが返されています。 また、関数が複数の引数を受け取る場合、下記のように複数のリストを記載します。

  2. mapc

    mapc は mapcar とは違い、関数を適用したリストを返さずに、元のリストを返します。 上記の例ではリストに含まれている名前を princ で出力しています。引数として使用したリストがそのまま戻り値として返されています。 mapcは副作用だけが欲しい場合に使用します。mapcarと比較すると新しいリストをconsで作成する処理がないため、高速です。

  3. mapcan

    mapcan は第一引数の関数が返すリストを nconc でつなげていきます。 mapcar は関数が返したリストをネストして追加しているのに対し、mapcan はリストをネストせずにつなげ合わせています。

参考
CLHS: Function MAPC, MAPCAR, MAPCAN, MAPL...