SECD Machine

月に一度来るあれが、来なくて、真っ青。おまけに発熱までするし。。。

こういう時は身近な人に相談してみるべき? いや、ちょっと心元なさそうだから ネットに相談してみよう。こういう話題はテレビでもかん口令が敷かれているみたいで なかなか話題にならないしね。普段、健康に関する話題で煽るくせに、こうい時は からっきし頼りにならないのは、マスコミですから。。。。

Windows Updateが0%から進まなくなったとき、失敗するとき、に試すこと

Windows Updateが遅い、進まない、終わらない、失敗する問題の解決方法

以前から、こういう話が有る事は知っていたけど、まさか自分が罹患するとは。これの 根本原因は、早くWindows10にしろしろウィルスに有るんだろうね。何喰わぬ顔して、 これはくぐり抜けてきたけど、今度は形を変えて脅迫してきた。

これじゃ、今猛威を奮っている、HDDを暗号化しておいて元に戻したかったら金払え ウィルスと何ら変わらんぞ。こういうのは、高い金払って入れているワクチンソフトも 効かないし。まあ、ワクチンソフトも、OSの動きが遅くなる、肝心な時にさっぱり 効かない。そんでいて、高い金をふんだくる。まあ、気休めソフトですからね。

でも、こういう症例に遭って、fixitとか言うゲーーツ閣下ご推薦の手当てプログラムが 有るとか、Windows機を最小構成で起動するには、msconfigしてbootタブから設定する とか、多少知見が拡がったか。

e と π と i の素敵な関係。

『虚数と複素数が見えてくる オイラーの発想』(技術評論社)なんてのを読んだのさ。 先生が時々言う、『実数の世界は、複素数の世界の一部が見えているに過ぎないのです』が、 身に沁みてきます。言語界ではどうか? 早速検証しましょ。

まずは近頃よく使うjulia君。i の代わりに im って後置する約束。eもpiも何の宣言を する事なく使えます。さすがに数学よりの言語です事。

julia> e ^ (1im * pi)
-1.0 + 1.2246467991473532e-16im

次はScheme代表のgosh君。eとpiは数学定数を使う宣言が必要。複素数は実部と虚部を 書かないと、エラーで刎ねられる。

gosh> (use math.const)
#<undef>
gosh> (exp (* 0+1i pi))
-1.0+1.2246467991473532e-16i

パイソンは複素数の数学を使うよ宣言が必要。iが(電流のiと)紛らわしいので、jを 使うという、工学系指向です。

Python 2.7.9 (default, Apr  2 2015, 15:34:55)
>>> import cmath
>>> cmath.exp( 1j * cmath.pi )
(-1+1.2246467991473532e-16j)

最近はrubyなんて使わないんだけど、ウブに何故か入っていたので試してみました。 やっぱり複素数使うぞ宣言が必要。cmathのファイルをちら見したら、Complexの虚部の 位置にpiを置く例が出てた。それも有りか。虚数単位のI (0+1i) ってのも使えるよって Webで見たけど、それらしいのは見つからず。

ruby 2.1.2p95 (2014-05-08) [i386-linux-gnu]
irb(main):001:0> require "cmath"
=> true
irb(main):002:0> CMath::exp( Complex(0, Math::PI) )
=> (-1.0+1.2246467991473532e-16i)
irb(main):003:0> CMath::exp( 1i * Math::PI )
=> (-1.0+1.2246467991473532e-16i)

perlも当然のごとくウブに居座っていたけど、もういいよね。代表的(オイラー的には) 言語で確かめたから。

4つの言語を試してみて、微妙に残る虚部の値。揃いも揃って、みな同じ結果。 libm.soの限界か。草葉の陰でオイラーさんが怒っておられるぞ。オイラーの 美しい数式(e^iπ = -1)を表現出来んとは、現代コンピュータも大した事無いな。

話はオイラーさんからちょっと逸れるけど、地底から宇宙を探る だったかニュートリノ素粒子の 世界だかいう 本を読んだら、電子の重さの話が出てきた。重さだから、9.11e-31 Kg とかいう とてつもなく小さい重さで表現すると思ったら違うのね。重さはエネルギー換算らしい。

物理学でもっと美しいと言われる式、 E = mc^2 を借りてきて、重さとエネルギーは 等価であるって所から来てるそうだ。強い力 弱い力とかの言葉が頻出する世界では 、この方がしっくりくるんでしょうな。納得至極。 特殊相対性理論-質量のMeV表示)

SECD Machine

今回からちょっとflispを離れて別の事をやります。とは言えLisp繋がりですけどね。

何回かsecdに出会った。ずっと以前にも取り上げているけど、コンパイラが出てきて 正直な所、余り乗り気じゃなかったんだ。でも、flispの中心がコンパイルしてからVMで 実行って仕組みになってたので、俄然興味が沸いてきたんだ。

百科事典で SECDマシン なんてのを引くと、 Welcome to SECD Mania なんていう、マニアなサイトが有るよと教えられた。こういうの有り難い。いきなりググルの 海に泳ぎ出してもオロオロするだけですからね。さしずめ、図書館に居るという司書さん ですかね。

pascal

昔の事なんで、使うにはFree Pascal コンパイラが 必要との事。

初めてオイラーが手にしたパソコンは、シャープのMZ-80K だった。クリーンコンピュータと 銘打っていたな。BASICに毒された国民機をおちょくっていたんですかね。 アセンブラとパスカルのカセットテープを購入して、その日の気分で切り替えて使っていた。

その後、MACに転んだんだけど、やはり開発をやりたくて、一番最初に買ったのがターボ・パスカル だった。次に買ったのがResEditだったかな。これは一般には売っていなくて、MACの デベロッパーに登録して手に入れた記憶がある。toolboxの使い方を知るには、Inside MACが 必要。1-5巻ぐらいまであったと思ったけど、主要部分はPascal語だった。

話が逸れた。 debianとかなら、次のようにしてパスカル関係者を用意しろとな。emacsで色を付けるには、 pascal-modeでOK。secdマシンのpascalソースは、サフィックスが .pp になってたので、 それを認識するように、init.elを設定。

ppってサフィクスはただのpascalじゃねぇぞ。 こちとら、オブジェクトパスカル様だって主張なんですかね。emacsにもopascal用が 有ったので、そちらを使う事にした。

;; pascal mode
(setq auto-mode-alist
      (cons (cons "\\.pp$" 'opascal-mode) auto-mode-alist))
sakae@uB:~$ sudo apt-get install  fp-compiler binutils
  :
The following NEW packages will be installed:
  fp-compiler fp-compiler-2.6.4 fp-units-rtl-2.6.4 fp-utils-2.6.4
0 upgraded, 4 newly installed, 0 to remove and 0 not upgraded.
Need to get 4,729 kB of archives.
After this operation, 37.8 MB of additional disk space will be used.
Do you want to continue? [Y/n]

でも、ウブって立ち上がるのが遅いのよね。ふと、OpenBSDにもFree Pascal Compilerが 有ったなと思って、近頃ご無沙汰のOpenBSDを起動。fpcって名前でパッケージに なってた。

[ob: Base_1]$ fpc
Free Pascal Compiler version 2.6.4 [2015/03/07] for i386
Copyright (c) 1993-2014 by Florian Klaempfl and others
/usr/local/bin/ppc386 [options] <inputfile> [options]
Put + after a boolean switch option to enable it, - to disable it
   :
*** press enter ***
   :

helpを出すのに、オプションが-hだったり、--helpだったりとアプリによってまちまち。 それに対して、こやつは初心者に親切。コンパイラなんだから、ソースを指定せにゃならん。 それを怠る輩には、説明してあげよう。そして、画面ががーと流れてしまって、途方に くれないように、more(less)をかませて、ゆっくり説明を読ませてあげよう。

こういう親切心は、教育界への制覇を狙ったものだな。だから、 本物のプログラマはPascalを使わない んだけどね。まあ、pascalが指定されている事も有るし、若かりし頃に戻ってみるのも、 案外オツなものかも知れないな。

しばし、pascalの自習。 第3章 PASCAL 入門

情報活用基礎プログラミング演習I そ して、ハロワでもやっておくか。

{ Free Pascal Hello, world. }

program Hello;

{$MODE OBJFPC}
{$CODEPAGE UTF8}
{$LONGSTRINGS ON}

uses
  SysUtils;

begin
  WriteLn(Output, 'Hello Pascal')
end.

なんか、思い出してきたみたい。

Henderson さんの SECD

This is the starting point of this package.

First SECD machine is called "Henderson"

It is an implementation of the original SECD machine from
the excellent book of P. Henderson "Functional Programming:
Application and Implementation", 1980, Prentice Hall.

起源は、この本で発表されたものか。この本、日本でも訳されて発売されていなかったかな? オイラー、カッコ付けて買った記憶が有るんだけど、違ったかな。

[ob: Base_0]$ ./make_all
Free Pascal Compiler version 2.6.4 [2015/03/07] for i386
Copyright (c) 1993-2014 by Florian Klaempfl and others
Target OS: OpenBSD for i386
Compiling secd.pp
Compiling secd_str.pp
Compiling secd_mem.pp
Compiling secd_cod.pp
Assembling secd_cod
Assembling secd_mem
Assembling secd_str
Assembling secd
Linking secd
983 lines compiled, 0.4 sec
Free Pascal Compiler version 2.6.4 [2015/03/07] for i386
Copyright (c) 1993-2014 by Florian Klaempfl and others
Target OS: OpenBSD for i386
Compiling self.pp
Assembling self
Linking self
25 lines compiled, 0.2 sec

昔からコンパイルは速かったのね。 実行してみる。

[ob: Base_0]$ ./self
Reading compiler code ...
Reading compiler source ...
--- SECD : ConsUse=  3277   SECD_loops=     0   AtomUse=61
--- stats: HeapUse=  1639   FreeNodes=      0   GCStPtr=0
Compiling compiler ...
--- SECD : ConsUse= 26988   SECD_loops= 64669   AtomUse=61
--- stats: HeapUse=  2452   FreeNodes=      7   GCStPtr=7

自身をコンパイルしてるって事? それらしい、compiler.lispを覗いてみると

(letrec compile
  (compile lambda (e)
    (comp e nil (quote (#app #stop))))

  (comp lambda (e n c)
    (if (atom e)
        (cons (add #ld (location e n)) c)
    (if (integer e)
        (cons #ldc (cons e c))
    (if (eq e nil)
        (cons #ldc (cons e c))
    (let
        (if (atom he)
            (if (lexleq he (quote inc))
                (if (lexleq he (quote cons))
                    (comp_00 he te n c)
                    (comp_01 he te n c) )
                (if (lexleq he (quote lexleq))
                    (comp_10 he te n c)
                    (comp_11 he te n c) ) )
            (comp_user he te n c))
        (he car e)
        (te cdr e))
  ))))

これがメインっぽい。それが翻訳されて

(#dum #ldf (#ld_0_1 #car #ld_0_0 #ld_1_10 #app_2 #trsel
   (#ld_0_1 #car #ld_0_0 #ld_1_11 #trapp_2) #ldc 256 #ld_0_1 #cdr #ld_0_0 #ld_1_15 #app_2 #add #rtn) #ldf
  (#ld_0_1 #ldc NIL #eq #trsel (#ldc NIL #rtn) #ld_0_1 #cdr #ld_0_0 #ld_1_14 #a_2 #ld_0_1 #car #ld_0_0 #app_1 #cons #rtn) #ldf
  (#ld_0_0 #ldc NIL #eq #trsel (#ld_0_1 #rtn) #ld_0_1 #ld_0_0 #cdr #ld_1_13 #app_2 #inc #rtn) #ldf
    :

こんな形になるとな。どうやら頭にシャープが付いているのが、SECDマシンが理解出来る 命令っぽい。そして、その命令を実行するのが、pascal語で書かれたアプリケーションって 事かな。

self.ppがメインで、secd_str.ppが、S式の読み込みと書き出し、secd_mem.ppがセル関係の ハンドリング、secd_cod.ppが実行系って事で、それぞれはモジュールになってるとな。

secd_loopって手続きが、いわゆるvmコードの実行を司っていて、ShowStatは、vmやら メモリー(セル)の使用状況の報告をしてくれるんか。

[ob: Base_0]$ ./secd fac
Reading code fac.secd  ...
--- SECD : ConsUse=    56   SECD_loops=     0   AtomUse=0
--- stats: HeapUse=    28   FreeNodes=      0   GCStPtr=0
Executing code ...
SECD: Loops=114  Cons=112
S=  (3628800)
E=  NIL
C=  (#stop)
--- SECD : ConsUse=   112   SECD_loops=   114   AtomUse=2
--- stats: HeapUse=    70   FreeNodes=      3   GCStPtr=3
[ob: Base_0]$ cat output.txt
3628800

例のfac.lispとfac.secdが用意されてたので、実行機械secdでfac.secdを実行してみた。 (fac 10)を求めるのに114サイクル必要だった。セルはfacの読み込み時点で56だったのが 実行後112に増えましたとな。

で、secdと言う割りにはdが見えてこない。pascal語を少々sapping。 secd_str.ppに

const
 MnemMax=40;
 SECDmnem:array[1..MnemMax] of TAtomS=
 ('ld-2',
  'ldc',
  'ldf',
  'none',
  'rtn',
  'dum',
  'dec',
  'int',
  'inc',
  'car',
  'cdr',
  'atom',
  'cons',
  'eq',
   :

こんな、対応表が用意されてる。secd_cod.ppには、それぞれの命令が 説明されてた。

{
 SECD commands:

  1 LD x y       s  e c           --> ((GetNth(GetNth(e,x),y) s) e c
  2 LDC          s  e (x c)       --> (x s)   e      c
  3 LDF          s  e (f c)       --> (x.e s) e      c
  4
  5 RTN          (x e' c' s) e c  --> (x s)   e'     c'
  6 DUM          s           e c  --> s      (nil e) c
  7 DEC     (x s) e c  --> (x-1 s)      e c
  8 INT     (x s) e c  --> (int?(x) s)  e c
  9 INC     (x s) e c  --> (x+1 s)      e c
 10 CAR     (x s) e c  --> (car(x) s)   e c
 11 CDR     (x s) e c  --> (cdr(x) s)   e c
 12 ATOM    (x s) e c  --> (atom?(x) s) e c
 13 CONS    (x y s) e c  --> (cons(x,y) s) e c
 14 EQ      (x y s) e c  --> (eq(x,y)   s) e c
   :

各命令の実行は、それぞれグループ分けされてる。例えば、引数が一つの場合、

 procedure UniCmd;
  begin
   if ChCnt=0 then Just(1);
   if cmd in [7,9] then if Regs[a].t<>int
    then Error('The argument must be int');
   case cmd of
     7:dec(Regs[a].v);
     8:if  Regs[a].t=int  then NewAtom('T',a) else NewAtom('F',a);
     9:inc(Regs[a].v);
    10:CarSelf(a);
    11:CdrSelf(a);
    12:if  Regs[a].t=atom then NewAtom('T',a) else NewAtom('F',a);
   end;
  end;

Just(1)ってのが、アリティのチェックだろうね。そしてコマンド番号で場合分けして から実行してる。carだとかcons等もVM命令の一種になってるのは、flispと一緒。 ってか、flispがsecdを真似たんだろうね。後は、pascal語を丹念に追って行くだけだな。

これらsecdマシンの最終系はBase_4に有るんだけど、

[ob: Base_4]$ ./make_all
Free Pascal Compiler version 2.6.4 [2015/03/07] for i386
Copyright (c) 1993-2014 by Florian Klaempfl and others
Target OS: OpenBSD for i386
Compiling secd.pp
Compiling sec_codes.pp
Compiling sec_lists.pp
Compiling sec_atoms.pp
Compiling sec_drivers.pp
sec_drivers.pp(5,33) Fatal: Can't find unit OldLinux used by sec_drivers
Fatal: Compilation aborted

こんなエラーを喰らってコンパイル失敗。OLDLinuxが無いって、どゆ事?

pascal 資料

ちょっと気になったので調べ。文法はいいから、rtlやfpcの資料が欲しいのよね。 いろいろと入り乱れていて、わけわかめ。

TCP Server

How to compile

ECHO server 昔見つけたのが 引っかかってきた。ラケットのコード短いなあと感心。

Lazarus Documentation/ja

Components and Code examples/ja

どうも混沌とした世界であります。もうこれぐらいにしておこう。

LandinさんのSECD

The mechanical evaluation of expressions に載った論文を近代的なRubyに置き換えた方がおられました。 P. J. Landin's original SECD Machine simulator + RETURN control 例によって、ウブのRubyで実行してみます。

  S nil
  E #4=nil
  C [((λ x.λ y.(x)(y))(λ y.y))(5), nil]
  D nil

  S nil
  E #4=nil
  C [5, [(λ x.λ y.(x)(y))(λ y.y), [APPLY, nil]]]
  D nil

  S [5, nil]
  E #4=nil
  C [(λ x.λ y.(x)(y))(λ y.y), [APPLY, nil]]
  D nil
   :
  S [5, nil]
  E #70963810=[[:y, 5], [[:x, {λ y.y #4#}], nil]]
  C [RETURN, nil]
  D [(nil #4# nil), nil]

  S [5, nil]
  E #4=nil
  C nil
  D nil

5

secd in Landoin も参考に。

Hiroi さんの SECD

なんやかんやと言っても、最終的には、 micro Scheme コンパイラの作成 にたどり着くのであります。goshの上に載せてSECD。 schemeは私のホームグラウンドですから、pascalとかrubyと違ってアウェイ感が 有りません。

$ gosh
gosh> (load "./vm36.scm")
#t
(use slib)
(require 'trace)
(require 'pretty-print)
(define pp pretty-print)
(trace vm)
#<closure (debug:trace-procedure debug:trace-procedure)>
>>> (define fact (lambda (n)
      (if (= n 1) 1 (* n (fact (- n 1))))))
(ldf (ld (0 . 0) ldc 1 args 2 ldg = app selr (ldc 1 rtn) (ld (0 . 0) ld (0 . 0) ldc 1 args 2 ldg - app args 1 ldg fact app args 2 ldg * tapp rtn)) def fact stop)
CALL vm () () (ldf (...) def fact stop) ()
  CALL vm ((closure ...)) () (def fact stop) ()
    CALL vm (fact) () (stop) ()
    RETN vm fact
  RETN vm fact
RETN vm fact
;(time (vm '() '() expr '()))
; real   0.001
; user   0.000
; sys    0.000
fact
>>> (fact 10)
(ldc 10 args 1 ldg fact app stop)
CALL vm () () (ldc 10 args 1 ldg fact ...) ()
  CALL vm (10) () (args 1 ldg fact app ...) ()
    CALL vm ((10)) () (ldg fact app stop) ()
      CALL vm ((...) ...) () (app stop) ()
        CALL vm () ((10)) (ld (...) ldc 1 args ...) ((() () (stop)))
        RETN vm 3628800
      RETN vm 3628800
    RETN vm 3628800
  RETN vm 3628800
RETN vm 3628800
;(time (vm '() '() expr '()))
; real   0.001
; user   0.000
; sys    0.000
3628800
>>> quit
(ldg quit stop)
CALL vm () () (ldg quit stop) ()
*** ERROR: unbound variable:  quit
Stack Trace:
  :
gosh> (pp *global-environment*)
((fact closure
       (ld (0 . 0)
           ldc
           1
           args
           2
           ldg
           =
           app
           selr
           (ldc 1 rtn)
           (ld (0 . 0)
               ld
               (0 . 0)
               ldc
               1
               args
               2
               ldg
               -
               app
               args
               1
               ldg
               fact
               app
               args
               2
               ldg
               *
               tapp
               rtn))
       ())
 (car primitive #[procedure])
   :
 (>= primitive #[procedure]))
30

etc

secd in ML こちらも学術感満載です。

Windows 10でUbuntuのシェル「Bash」が動き始める!

進まないWindows Update、Windows 7向けの更新は慢性的な問題を抱えている?