#:g1: 色々な言語でCommon Lispのコードを書いてみよう

Posted 2018-08-27 17:23:54 GMT

色々な言語でCommon Lispのコードを書いてみたら、どうかなと思い試してみました。
だからなんなの、というような試みです。

コード例はお馴染みのfibにします。

Common Lisp

大元のCommon Lispです。
quoteを付ければデータになりますが、一応listでリストを生成するものも書いてみます。

'(defun fib (n)
   (if (< n 2)
       n
       (+ (fib (1- n))
          (fib (- n 2)))))

(list 'defun
      'fib
      (list 'n)
      (list 'if
            (list '< 'n '2)
            'n
            (list '+ 
                  (list 'fib (list '1- 'n))
                  (list 'fib (list '- 'n 2)))))

当然ながらevalすれば、コードとして実行できます。

Racket

まあ、RacketもCommon Lispもそのまんまですね。
1-というシンボルは関数名としては不可だった気もします。

'(defun fib (n) (if (< n 2) n (+ (fib (1- n)) (fib (- n 2)))))

defun等々の関数を定義すれば、そのまま動かせると思います。

Python

PythonではCLのリストに相当するものは配列になるでしょう。
ASTやシンボルへのアクセスもできるようですが、とりあえず、面倒なのでシンボルは文字列としておきます。

['defun',
 'fib',
 ['n'],
 ['if',
  ['<', 'n', 2],
  'n',
  ['+', ['fib', ['1-', 'n']], ['fib', ['-', 'n', 2]]]]]

上のコードを動かすにはインタプリタを作成する感じなんでしょうか。

Ruby

RubyもPythonと似た感じですが、シンボルがあるので使ってみました。

[:defun,
 :fib,
 [:n],
 [:if, [:<, :n, 2], :n, [:+, [:fib, [:"1-", :n]], [:fib, [:-, :n, 2]]]]]

Erlang

何故Erlangという気もしますが、Prologっぽいので試してみました。
やはりシンボルがあるので扱いが楽です。

[defun,fib,[n],['if',['<',n,2],n,['+',[fib,['1-',n]],[fib,['-',n,2]]]]]

Prolog

Prologは、Lispと同様、基本のデータ型がリストです。Lispのシンボルはアトムに相当するでしょうか。

[defun,fib,[n],[if,[<,n,2],n,[+,[fib,[1-,n]],[fib,[-,n,2]]]]]

Julia

最近ブレイクしつつあるような気がするJuliaですが、シンボルがあるので、そこそこ素直に書けます。

[:defun, :fib, [:n], [:if, [:<, :n, 2], :n, [:+, [:fib, [Symbol("1-"), :n]], [:fib, [:-, :n, 2]]]]]

データをコードにする仕組みが割と身近に存在するようで、文字列をパーズしてExpr型というコードに変換することが可能です。

julia> xpr="function fib(n)
         if n < 2
            n
          else
            fib(n - 1) + fib(n - 2)
         end
       end"

julia> Meta.parse(xpr) :(function fib(n) #= none:2 =# if n < 2 #= none:3 =# n else #= none:5 =# fib(n - 1) + fib(n - 2) end end)

julia> Meta.show_sexpr(Meta.parse(xpr)) (:function, (:call, :fib, :n), (:block, :(#= none:2 =#), (:if, (:call, :<, :n, 2), (:block, :(#= none:3 =#), :n ), (:block, :(#= none:5 =#), (:call, :+, (:call, :fib, (:call, :-, :n, 1)), (:call, :fib, (:call, :-, :n, 2))) )) ))

コードをExprで直接記述することもできるようで、この辺りは、まんまLispの前置記法ですね。

Expr(:function, Expr(:call, :fib, :n), 
     Expr(:if, Expr(:call, :<, :n, 2), 
             :n,
             Expr(:call, :+, 
                    Expr(:call, :fib, Expr(:call, :-, :n, 1)), 
                    Expr(:call, :fib, Expr(:call, :-, :n, 2)))))

(追記) Squeak/Pharo Smalltalk

ブログの内容が謎コンテンツでしたが、意外にもSmalltalk方面から反応を頂きました。
ありがとうございます🙇

シンボルがあるSmalltalkもかなりLispっぽく書けますね。しかも丸括弧。

まとめ

Common Lispは、プログラムを文字のつづりというよりは、言語処理系のリスト型とシンボルで記述しますが、他の言語のデータ型を使ってCommon Lispのコードを書いてみたら面白いかなと思って試してみました。

当然ながら、やっぱり、Lisp、Prologあたりは、この辺りの処理はしやすいですね。

Juliaは数値計算にフォーカスしているものと思っていましたが、案外Lisp的なコード=データな文化も継承しているようで、なかなか面白いと思いました。


HTML generated by 3bmd in LispWorks 7.0.0

comments powered by Disqus