日記:撤収してsympy

日記。

 

目の前の問題:

柔軟な原価計算(というか利益管理)の仕組みを作りたかった。

しかし原価計算・利益管理は客先・営業毎に変なロジックが存在する(そして派生する)ため、RDBMS上でそれを網羅する不思議関数・不思議テーブルを作成・維持する事は無理ゲー。

 

やりたかったこと:

ユーザサイドのビジネスルールをユーザに入力してもらって、これを解く。

手続きを入力させるのではなく、ルールを入力させる。

ぶっちゃけ、STUDENT(1960年ぐらいのプログラム)みたいな事をやりたかった。

RDBMS上で単体で動く事が望ましい。

 

やってみたこと:

T-SQL上にSchemeに似た言語の実行系を実装、その上に数式処理プログラムを実装することを試みた。

 

やってみた結果:

生涯労働時間の0.1%ぐらいを投入して(そして今年のゴールデンウィーク前半を全て投入して)T-SQL上にSchemeもどきを仮実装し、それの最適化を試みた結果として、T-SQL上のインタプリタもしくはコンパイラは常識的な処理系の1/10000程度の速度しか得られず(コンパイラにしても全然速くならないんだぜ!)、実用に至らないと判断した。

あと多分合計2万行を超える。メンテできん。

 

結論:撤収

 

 

で、傷心を抱えつつ、Mathematicaかなーでもあいつ面倒だなーもうパーサ書く気力ないなー完全に撤収しようかなー溜まってる他の仕事したくないなーどう言訳しようかなーとかブラブラ検索してたら、驚くべき事実を発見。

 

python3はユニコード文字を識別子に使用可能らしい。

 

以下、凄くアレな原理動作確認コード。

これpythonのプログラムなんだぜ。

 

from sympy import *

鉄の単価_円pkg= symbols('鉄の単価_円pkg')
素線径_mm = symbols('素線径_mm')
全長_mm = symbols('全長_mm')
製品単重_gp本 = symbols('製品単重_gp本')
製品体積_mm3p本= symbols('製品体積_mm3/本')
鉄の比重_gpmm3 = symbols('鉄の比重_g/mm3')

全長と素線径と製品体積 = Eq(製品体積_mm3p本,( (素線径_mm**2)*3.14/4*(全長_mm+ 素線径_mm*1.9)))
製品体積と製品単重 = Eq(製品単重_gp本,製品体積_mm3p本*鉄の比重_gpmm3/1000)
鉄の単価設定 = Eq(鉄の単価_円pkg,130)
全長設定 = Eq(全長_mm,40)
素線径設定 = Eq(素線径_mm,2.3)
鉄の比重設定 = Eq(鉄の比重_gpmm3,7.9)
solve( (全長と素線径と製品体積,製品体積と製品単重,鉄の単価設定,全長設定,素線径設定,素線径設定,鉄の比重設定))

[{全長_mm: 40.0000000000000,
素線径_mm: 2.30000000000000,
製品体積_mm3/本: 184.253080500000,
製品単重_gp本: 1.45559933595000,
鉄の単価_円pkg: 130.000000000000,
鉄の比重_g/mm3: 7.90000000000000}]

 

コードが中途半端なのは許せ。これ使うこと前提で行くか。

#本当は条件式付きの関数定義とその地味な変数消去をしたかったんだけどナーナーナー

もうGWは仕事しない…いやそれは無理だが、プログラムはもう止め。

明日は温泉だ!

(tarai 6 3 0) を計算するのに30秒掛かる件

日記。

 

T-SQL上に実装途中のSchemeモドキインタプリタ

(tarai 6 3 0)  ⇒ 6 

で30秒(GC一回動かして50秒)掛かる。

(tarai 12 6 0) 

は帰ってくる気がしないのでまだやってない。

今日寝る前に叩こう。

 

BEGIN TRANSACTIONCOMMITの間に入れてこれ。

TRANSACTION外すと10倍遅くなる。

プロファイラ噛ますとさらに3倍遅くなる。

 

整数型としてbigintを

 

GCはちょっと適当。

まだインタフェース書いてないけど継続もそこそこ真面目に実装した。

 

お楽しみはこれから・・・あ、まだマクロ書いてねぇやorz

 

再帰ってすごい

思い付きでちょっと腐った言語(その名はT-SQL)の上にS式言語パーサ(目標Scheme R5RS)を載せてみてるんだが、

 

T-SQLはストアドetcのネストが32回までです。

繰り返します。

T-SQLはストアドetcのネストが32回までです。

この中でREP(Lは無い)しろと。 

つまりT-SQL上の再帰禁止。2000行ほど書いてからこの事実に直面した。

再帰クエリ書けばいいんだけど俺にそんな知能は無い。

 

で、理論上は行けるんで書いてみてたんだけど、例えばとある癖のない関数で、深呼吸して一気に再帰なしを書けた(そしてバグが一個出た)場合に、

  • 再帰あり:32行
  • 再帰なし:179行(かなりコメント行もあるが、これ削除したら後日死ぬ)

となった。

 

再帰すげぇ。先人に感謝。

はじめてのScheme

記念に。読むなよはずかしい。

値渡しであることが信じられなかったので処理系インストール。

値渡しだなぁ。

 

> "HelloWorld"
"HelloWorld"

> '()
'()

> '("HelloWorld")
'("HelloWorld")

> (define vhello "HelloWorld")
> vhello
"HelloWorld"

> (display vhello)
HelloWorld

> (define fhello ( lambda () "HelloWorld"))
> fhello
#<procedure:fhello>

> (fhello)
"HelloWorld"

> (define sayit (lambda () vhello))
> (sayit)
"HelloWorld"

> (define sayit2 (lambda (s) s))
> (sayit2 vhello)
"HelloWorld"

> (define sayit4 (lambda (s)(set! s "GoodByWorld!") s))
> (sayit4 vhello)
"GoodByWorld!"
> vhello
"HelloWorld"

> (define displayit(lambda (s) (display s)))
> (define sayit5(lambda (s l) (l s)))
> (sayit5 vhello displayit)
HelloWorld

> (define displayit2(lambda (s) (display (string-append s "!"))))
> (sayit5 vhello displayit2)
HelloWorld!

> (define sayit6(lambda (s l) (set! l displayit2)(l s)))
> (sayit6 vhello displayit)
HelloWorld!
> (sayit6 vhello displayit2)
HelloWorld!
> (sayit5 vhello displayit)
HelloWorld

???

お前大域変数変更できないの?…タバコ一本吸って気づいた。

 

> (define changeworld(lambda()(set! vhello "GoodByWorld!") vhello))
> (changeworld)
"GoodByWorld!"
> vhello
"GoodByWorld!"

 

そりゃそうだ。

ちょっと昨日の朝小人さんが呟いたので scheme を勉強していたのだが、継続が分からんかった。

 

Revenge of the Nerds

 

を読んでたらちょっと新しい学習平原(←...一般的な用語じゃないっぽい?)に入れた。

 

LISP系のプログラムはリストなんだから、現在居る点から「トップレベル」に至るまでの表現はリストの操作で得られるんだな。

 

「トップレベル」という言葉はここに至るまでに彷徨ったサイトで見つけたんだがトップレベルってどこだよ…REPLschemeで実装する場合と他の言語で実装する場合で定義違わんか?明日仕様書、つうかR5何とか読もう。