ラベル Lisp の投稿を表示しています。 すべての投稿を表示
ラベル Lisp の投稿を表示しています。 すべての投稿を表示

2015/05/29

Lispの新しい方言をいくつか

 Lispといえば方言ですが, 新しい(2000年以降に登場した)方言がたくさんあって, 覚えきれないのでメモ.


 によれば, ErlangVM上で動くLisp, LFEという方言があるそうです. 最初に登場したのは, 2008年なのだそうで, 2007年に登場したClojureとは一年違いです.

 英語版のWikipediaのLispの記事を見ると,
There are several new dialects of Lisp: ArcHyNuClojureLiskellLFE (Lisp Flavored Erlang) and Racket.
とあり,  Common Lisp, Emacs Lisp, Scheme, Clojure以外にも様々な方言が存在しています.

 Arcは, 特徴はいまいちよくわかりませんが, Paul Grahamによる方言とその実装. Hyは, PythonVM上で動作するLispで前に記事を書きました. Nuは, Objective-Cで書かれていて, MacOSXのアプリケーション向けのスクリプト言語で, Semantics的にはLispよりもRubyに近いそう. Liskellは, 名前からなんとなく想像がつきますが, HaskellのSyntaxをLisp風にしたものです. しかし, 実装は見当たらず, ネット上には論文しか落ちていません. (追記 : Rudolph Miller さんにGitHubに実装があると教えていただきました.) Racketは, もともとSchemeの処理系の一種でしたが, RnRS(Schemeの仕様書)から独立してRacketという言語になったものです.

 他にも調べると色々出てきました. どうやら, VM+Lispという組み合わせ(Clojure, Hy, LFE)が多いようなので, Luaで調べてみると, Moonlispというのがでてきましたが, これは, Luaのコード(VMのバイトコードなどではなく, 言語としてのLuaのコード)へコンパイルされるもののようです. CLR(.NET)では, L#, JavaScriptでは多すぎて調べきれませんが, ここ(JavaScript Lisp Implementations)に, そのリストがあります.

 また, Egisonというパターンマッチに重点をおいた方言がありますが. このあたりは, パターンマッチに否定的なClojureとは対照的かもしれません.

2015/01/05

Hy(lang), Lisp風味のPythonを使ってみた

 hy(lang)は, Lispです.

 公式にあるように, pipから簡単にトライできます.


 以下の記事は, hyのversion 0.10.1についての内容です.

 シンタックスは, 見た目, ほぼClojureにそっくりですが, cond, let式などをはじめとして, 微妙に異なる部分があるのと(どちらかといえばSchemeやRacketに近い), Python風の構文がいくつか含まれているなど, yet-another Clojureだと思ってプログラムを書こうとすると, 結構嵌まりました.

 ClojureからNumpyとか使ってみたい気もしますが, ベースがPythonであることもあり, hylangは, Clojureとは別の道を歩もうとしているようです.

 何回も使いまわしていますが, 8Queen問題の解法のプログラムを, Clojureで,書くと以下のような感じになるところを,
;; slove the 8 queen problem
(defn conflict? [x y others]
  (and (not (empty? others))
       (let [x1 (ffirst others) y1 (second (first others))]
         (or (= x x1) (= y y1)
             (= (- x x1) (- y y1)) (= (- x x1) (- y1 y))
             (conflict? x y (rest others))))))

(defn put-a-queen [x y others]
  (cond
   (< 7 x) false
   (not (conflict? x y others)) [x y]
   :else (put-a-queen (inc x) y others)))

(defn solve [x1 y1 answer1]
  (loop [x x1 y y1 answer answer1]
    (let [rests (rest answer)]
      (cond
       (and (< 7 x) (= 0 y))
       nil
       (< 7 y)
       (cons answer (solve (inc (ffirst answer)) (dec y) rests))
       :else
       (if-let [xy (put-a-queen x y answer)]
         (recur 0 (inc y) (cons xy answer))
         (recur (inc (ffirst answer)) (dec y) rests))))))

;; make the list of solutions
(def solutions (solve 0 0 []))
 hyで書くと, 次のようになりました.
;; slove the 8 queen problem
(require hy.contrib.loop)
(require hy.contrib.anaphoric)

(defn conflict? [x y others]
  (and (not (empty? others))
       (let [[x1 (car (car others))] [y1 (car (cdr (car others)))]]
          (or (= x x1) (= y y1)
              (= (- x x1) (- y y1)) (= (- x x1) (- y1 y))
              (conflict? x y (cdr others))))))

(defn put-a-queen [x y others]
  (cond
   [(< 7 x) false]
   [(not (conflict? x y others)) [x y]]
   [:else (put-a-queen (inc x) y others)]))

(defn solve [x1 y1 answer1]
  (loop [[x x1] [y y1] [answer answer1]]
    (let [[rests (cdr answer)]]
      (cond
        [(and (< 7 x) (= 0 y))
         nil]
        [(< 7 y)
         (cons answer (solve (inc (car (car answer))) (dec y) rests))]
        [:else
         (ap-if (put-a-queen x y answer)
           (recur 0 (inc y) (cons it answer))
           (recur (inc (car (car answer))) (dec y) rests))]))))

;; make the list of solutions
(def solutions (solve 0 0 []))
 ぱっと見は, Clojureとそっくりに書けることがわかります. もちろん, この書き方がhyの標準的なスタイルかどうかは分かりませんが. def/defnの記法は, Clojureと同じで, 大括弧([])を多様する書き方が, 全体をClojureっぽく見せているのだと思われます.

 condとlet式の部分は, 要素を偶数個並べる書き方ではありません. condは, 条件式とそれに対応する節のペアを括弧で囲います. letも, 変数を表すシンボルと, 割り当てる値を計算する式をリストで組にしたものを並べます(この辺は, Clojure感覚で書いていると, エラーが続出して, 結構嵌まりました).
 true/falseも, #t/#fではなく, true/falseのキーワードで表します. (Schemeと混同してました. 2015/02/02)
(defn put-a-queen [x y others]
  (cond
   [(< 7 x) false]
   [(not (conflict? x y others)) [x y]]
   [:else (put-a-queen (inc x) y others)]))
 さらに, car/cdrが復活しています(ただし, first/restも使えます).  loop/recurスペシャルフォームが使えますが, デフォルトでは使えません. contribからロードする必要があります.
(require hy.contrib.loop)
 こんな感じで, 割と表記上の問題は解決出来たのですが, リスト操作が不可解で, 結構難しかった印象です.

 一つは, empty?の特殊さで, これはリストの長さを計るのですが, (= (len ls) 0)の結果を返します. リストにrestをかけるとitertools.isliceというオブジェクトが生成されますが, このitertools.isliceオブジェクト, countableではないようで, (empty? (rest [1 2]))などと書くとエラーが出ます. そもそもempty?は, リストの長さを数える必要がないのですが, この辺はまだ, 実装途中といった感じなのかもしれません.
=> (rest [1 2])
<itertools.islice object at 0x271d208>
=> (empty? (rest [1 2]))
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/home/uks/Dropbox/langs/lisps/hy/example/env/local/lib/python2.7/site-packages/hy/core/language.hy", line 124, in is_empty
    (= 0 (len coll)))
TypeError: object of type 'itertools.islice' has no len()
=> (cdr [1 2])
[2L]
 ちなみにcdrが返すのはitertools.isliceではないようです.

 さらに, (憶測ですが)nil = Noneだったり, car ≠ first, cdr ≠ restだったり, 各関数がどのような内部クラスやオブジェクトの操作に対応しているのか知らないと, 嵌まるポイントがいくつかありました.
=> (first (rest (cons 1 None)))
=> (car (cdr (cons 1 None)))
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/home/uks/Dropbox/langs/lisps/hy/example/env/local/lib/python2.7/site-packages/hy/models/list.py", line 43, in __getitem__
    ret = super(HyList, self).__getitem__(item)
IndexError: list index out of range
 ネガティブなコメントが多くなってしまいましたが, 個人的には, Syntaxの観点から見ると, Clojureの書きにくかった部分が書きやすくなってるなーという印象です. Clojureは括弧の数を減らそうとしている箇所(cond, letなど)が多数見受けられますが, 逆にそこが仇となっている感じでしたがhylangでは元に戻っていました. リスト内包記法なんかも, Clojureのforとは比べ物にならないほど読みやすいです. リーダマクロも使い放題ですし.

 同じ機能を持つ関数やスペシャルフォームが, 複数名前があることが多いです. 例えば, 前述したcar/firstやdefn/defun, do/prognなどがあります.

 アナフォリックマクロが大量に定義されていて, contribをロードすると, 使えるようになります. anaphoricなのでapが頭につくみたいですね. ap-ifで, itに条件式の結果をbindします.
=> (require hy.contrib.anaphoric)
=> (ap-if true it false)
True

2014/08/29

Lispの仕様書, リファレンスマニュアル

(LISP 1.5 PRIMER (BY (CLARK WEISSMAN)) (1967)
http://www.softwarepreservation.org/projects/LISP/book/Weismann_LISP1.5_Primer_1967.pdf

LISP 1.5 Programmer's Manual 2nd ed, 15th printing (1985)
http://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf

Mac Lisp Reference Manual (1974.08.04)
http://www.softwarepreservation.org/projects/LISP/MIT/Moon-MACLISP_Reference_Manual-Apr_08_1974.pdf

Franz Lisp Manual (1983)

Lisp Machine Manual 6th ed (Zeta Lisp) (1984.06)
http://common-lisp.net/project/bknr/static/lmman/frontpage.html

Common Lisp HyperSpec
http://www.lispworks.com/documentation/HyperSpec/Front/index.htm

R5RS〜R7RS, SRFI
http://scheme-reports.org/

R4RS(Revised 4 Report on the Algorithmic Language Scheme) (1991)
http://people.csail.mit.edu/jaffer/r4rs_toc.html

R5RS(Revised 5 Report on the Algorithmic Language Scheme) (1998)
http://www.schemers.org/Documents/Standards/R5RS/

R6RS(Revised 6 Report on the Algorithmic Language Scheme) (2007)
http://www.r6rs.org/

R7RS(Revised 7 Report on the Algorithmic Language Scheme) (2013)
http://trac.sacrideo.us/wg/wiki/R7RSHomePage

その他, LispといえばEmacs Lisp, Clojure, Arcなど.