clojureを分解する(5)
昔から何でも分解してみたくなる性分の私は、今咲き誇る 桜の花を、1片、2片...
と、何とも風情のない事をしてしまって、ちょっと反省してます。
でも、こんな事は許してもらえますよね。
[sakae@fb ~]$ gosh-rl
gosh> (define (foo n)
..... (* n n))
foo
gosh> (disasm foo)
main_code (name=foo, code=0x81af640, size=4, const=0, stack=1):
args: #f
0 LREF0-PUSH ; n
1 LREF0 ; n
2 NUMMUL2 ; (* n n)
3 RET
#
とか
[sakae@fb ~]$ sbcl
* (defun foo(n)
(+ n n))
FOO
* (disassemble 'foo)
; disassembly for FOO
; 598538B4: 8BD6 MOV EDX, ESI ; no-arg-parsing entry point
; B6: 8BFE MOV EDI, ESI
; B8: E87BC87AA7 CALL #x1000138 ; GENERIC-+
; BD: 7302 JNB L0
; BF: 8BE3 MOV ESP, EBX
; C1: L0: 8B75F4 MOV ESI, [EBP-12]
; C4: 8D65F8 LEA ESP, [EBP-8]
; C7: F8 CLC
; C8: 8B6DFC MOV EBP, [EBP-4]
; CB: C20400 RET 4
; CE: CC0A BREAK 10 ; error trap
; D0: 02 BYTE #X02
; D1: 18 BYTE #X18 ; INVALID-ARG-COUNT-ERROR
; D2: 4D BYTE #X4D ; ECX
NIL
さて、clojureのapiを見ていたら、面白いものを発見
user=> (class 123)
java.lang.Integer
user=> (class 1.23)
java.lang.Double
user=> (class (/ 1 3))
clojure.lang.Ratio
user=> (class 11111111111111111111111111111111111111111)
java.math.BigInteger
user=> (class false)
java.lang.Boolean
user=> (class nil)
nil
user=> (class ())
clojure.lang.PersistentList$EmptyList
user=> (class '(1 2 3))
clojure.lang.PersistentList
user=> (class :a)
clojure.lang.Keyword
user=> (class [])
clojure.lang.PersistentVector
user=> (class {})
clojure.lang.PersistentHashMap
user=> (class #{})
clojure.lang.PersistentHashSet
user=> (class (def n 3))
clojure.lang.Var
user=> (class (fn [] nil))
user$eval__40$fn__42
user=> (class +)
clojure.core$_PLUS___2959
user=> (class (range 1 3))
clojure.lang.Range
user=> (class (defstruct foo :a :b))
clojure.lang.Var
user=> (class foo)
clojure.lang.PersistentStructMap$Def
user=> (class (struct foo "aa" "BB"))
clojure.lang.PersistentStructMap
きりがないので、これぐらいにしますが、これって、rubyのあれと一緒ですね。
[sakae@fb ~]$ irb
irb(main):001:0> 3.class
=> Fixnum
irb(main):002:0> 33333333333333333333333333333.class
=> Bignum
irb(main):003:0> [1,2,3].class
=> Array
clojureの方は、Javaで賄えるのは、Javaに丸投げ(継承って言うでしたっけ?)
してて、楽そうな感じがします。その点、Rubyって、ちょっと可哀想。
rubyには、riなんて言う素敵な機能がついていますが、clojureではどうかな?
user=> (doc +)
-------------------------
clojure.core/+
([] [x] [x y] [x y & more])
Returns the sum of nums. (+) returns 0.
nil
user=> (doc cons)
-------------------------
clojure.core/cons
([x seq])
Returns a new seq where x is the first element and seq is
the rest.
nil
これは、emacs-lispから輸入したものですね。
今、ふとapiを見ていたら、inspectorなるものが目に入ってきました。
物は試しとばかり
user=> (use 'clojure.inspector)
nil
user=> (inspect 1)
#<JFrame javax.swing.JFrame[frame0,0,0,400x400,layout=java.awt.BorderLayout,title=Clojure Inspector,resizable,normal,defaultCloseOperation=HIDE_ON_CLOSE,rootPane=javax.swing.JRootPane[,4,30,392x366,layout=javax.swing.JRootPane$RootLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=16777673,maximumSize=,minimumSize=,preferredSize=],rootPaneCheckingEnabled=true]>
窓が出てきましたよ。きっとこれは、JavaBeansあたりと結合するための、予行
演習に違いない。でも、(def x '(1 2 (3 4 5) 6 (7 8 (9)))) しておいて
(inspect-tree x) すると、笑える。どうせなら、和田先生に対抗して、
cellの箱をきちんと書いて欲しいぞと。
それじゃ、またまた面白いものがあったので、、、
user=> (doc cycle)
-------------------------
clojure.core/cycle
([coll])
Returns a lazy (infinite!) seq of repetitions of the items in
coll.
nil
user=> (def a (cycle '(1 2 3)))
#'user/a
user=> a
(1 2 3 1 2 3 1 2 3 ..........
java.lang.OutOfMemoryError: Java heap space
user=>
こんなの初めてみましたよ。ちなみに、cycleは、どんな定義かと言うと
(defn cycle
"Returns a lazy (infinite!) seq of repetitions of the items in
coll."
[coll]
(when (seq coll)
(let [rep (fn thisfn [xs]
(if xs
(lazy-cons (first xs) (thisfn (rest xs)))
(recur (seq coll))))]
(rep (seq coll)))))
ちなみに、肝は
(defmacro lazy-cons
"Expands to code which produces a seq object whose first is
first-expr and whose rest is rest-expr, neither of which is
evaluated until first/rest is called. Each expr will be evaluated at most
once per step in the sequence, e.g. calling first/rest repeatedly on the
same node of the seq evaluates first/rest-expr once - the values they yield are
cached."
[first-expr & rest-expr]
(list 'new 'clojure.lang.LazyCons (list `fn (list [] first-expr) (list* [(gensym)] rest-expr))))
のようです。更に、遡って、clojure.lang.LazyConsを見ると
package clojure.lang;
final public class LazyCons extends ASeq{
final private static ISeq sentinel = new Cons(null, null);
IFn f;
Object _first;
ISeq _rest;
public LazyCons(IFn f){
this.f = f;
this._first = sentinel;
this._rest = sentinel;
}
:
のように定義されてました。ちなみに、Javaの事を何も知らない私は、
浅煎り珈琲Java アプリケーション入門のお世話になっております。