clojure-japan

athos 2015-06-22T04:06:10.000489Z

関数定義も普通にできるみたい

athos 2015-06-22T04:12:15.000493Z

セッションタイムアウトは設定されてると思うけど、どのくらいの時間有効なんだろう

ayato_p 2015-06-22T04:13:41.000494Z

有効というのは定義がいつまで使えるか、というこtです?

athos 2015-06-22T04:17:43.000495Z

です。サンドボックスにはclojailを使ってると思うんですけど、仕組み上一定時間で定義というか名前空間を捨てていかないとGCできないので。

athos 2015-06-22T04:18:30.000496Z

https://github.com/Raynes/clojail

ayato_p 2015-06-22T04:19:54.000498Z

僕もそれ前に気になりましたけど、気にしないことにしました(

athos 2015-06-22T04:20:46.000499Z

(f 42)

athos 2015-06-22T04:20:54.000500Z

誤爆

athos 2015-06-22T04:21:09.000502Z

うーん

athos 2015-06-22T04:22:42.000503Z

あと、clojailはサンドボックスライブラリとしてもわりとザルなので、あまり使うのもどうなんだろうという気が

ayato_p 2015-06-22T04:23:23.000504Z

具体的にどのへんがです?(ザル

athos 2015-06-22T04:25:13.000506Z

clojailってコードをトラバースしてブラックリストに載ってるシンボルがコード中に出現しないかチェックしてるんですけど、ブラックリストに載ってるシンボルでもメタプログラミング的に生成してしまうと使えてしまう、とか

athos 2015-06-22T04:26:38.000508Z

みたいな感じで、evalとかリスクのある名前は使おうとするとSecurityErrorになるようになってます。これがブラックリスト。

ayato_p 2015-06-22T04:29:53.000514Z

闇の技術だ…

athos 2015-06-22T04:30:52.000515Z

こんな感じに、evalってシンボルそのものじゃなくて、シンボルevaとシンボルlをコンパイル時につなげるみたいなことをすると、簡単に突破できます

ayato_p 2015-06-22T04:31:46.000516Z

理屈は分かりますけど実際それを防ぐのだいぶしんどいですよね

athos 2015-06-22T04:34:39.000517Z

なので、Clojureの真面目なサンドボックスを作ろうと思った場合、Clojureのコードを見るんじゃなくて、Javaのサンドボックス機能を使うなりして、実行時に「fooクラスのbarメソッドが呼ばれた」みたいなのを検知しないとダメだと思います

ayato_p 2015-06-22T04:35:13.000518Z

なるほど

athos 2015-06-22T04:38:13.000519Z

ただ、Javaのセキュリティ機能でメソッド呼び出しを禁止するためには、そのクラスがそういう実装になってないとダメなので、「Clojureのコアクラスのこのメソッドを呼び出しちゃいけない」っていうのを後づけで指定できないので、現実的にはさっきの方針はかなり難しいです

ayato_p 2015-06-22T04:40:53.000520Z

Clojure そのものを修正する必要が出てくるということですかねー。真面目にやるなら。

athos 2015-06-22T04:43:51.000521Z

もうちょっと現実的な方法としては、自前でクラスローダを用意して、Clojureコアのクラスをロードするときに特定のメソッドにセキュリティチェックを挿入するロードタイムウィービングとかが考えられますけど、まぁこっちにしてもヘビーなことには変わりないですね。

ayato_p 2015-06-22T04:45:47.000522Z

(Java ってそんなこと出来るんですねっておどろいているところ)

athos 2015-06-22T04:48:08.000523Z

クラスローダはバイト配列としてのJavaバイトコードからクラスを生成できるんで、そのバイト配列の段階ならお好きなように煮るなり焼くなりできます😉

ayato_p 2015-06-22T04:50:10.000524Z

Java を煮る技術…

athos 2015-06-22T04:52:20.000525Z

Clojureの場合、コンパイラとクラスローダがかなり密に結合してる感じがするんで、自前のクラスローダを差し挟んだときにまともに動くのかは分からないですね。やったことない。

icalo35 2015-06-22T05:49:22.000534Z

なんかヤバい事してるー!?(ガビーン)

icalo35 2015-06-22T05:49:54.000535Z

これ無限シーケンス評価しようとしたら止めてくれるんですよね?(不安顔)

athos 2015-06-22T05:50:34.000536Z

やばいことはしてません!(まだ)

athos 2015-06-22T05:56:18.000538Z

さすがに他のチャンネルに影響でそうでこわい

icalo35 2015-06-22T05:56:53.000539Z

タイムアウトしてても割とこわい

athos 2015-06-22T05:57:36.000540Z

タイムアウトまでの間、メモリ食うのは避けられないですからね

ayato_p 2015-06-22T05:58:17.000541Z

(・ω<)

icalo35 2015-06-22T05:58:53.000542Z

ClojureベースのDSLみたいなの作ろうとする場合、サンドボックスというかクリーンルーム?的なものを作るのって結構大変なんですね~

icalo35 2015-06-22T06:01:03.000543Z

いや、ちゃんと機能限定すればそうでもない……?

athos 2015-06-22T06:02:07.000544Z

汎用的なものを作るのは難しいと思います。今だとむしろ、仮想環境を作っては捨てる運用の方がよっぽど安く実現できそうな気がします。

icalo35 2015-06-22T06:07:03.000545Z

仮装環境といいますと、REPLサーバみたいなものを作っては捨てる、みたいなイメージなんでしょうか(ピンときてない)

athos 2015-06-22T06:11:35.000546Z

コンテナ型の仮想化技術を使って、リクエストごとにコンテナを作るようなのをイメージしてました

2015-06-22T07:23:14.000550Z

あるある > alter-var-root!

2015-06-22T07:24:40.000551Z

clojureはいまいち ! の有無の統一が取れてない感ある。 set! swap! とかは ! 付き、 aset alter-var-root とかは ! なし

athos 2015-06-22T07:29:09.000552Z

どこかで、トランザクションの中で呼び出すべきじゃないものに!がついている、という説を見た気がしますけど、これもすべてをカバーできるルールではないでしょうね

athos 2015-06-22T07:31:23.000553Z

ただ、この説だと破壊的操作でない io! マクロになんで!がついているのかっていう説明にはなるんですよね

2015-06-22T07:33:13.000554Z

おー、なるほどです

2015-06-22T10:13:12.000555Z

そういえばかなり前に出てた話題ですが、condのインデントが深くなる問題、自分は勝手に cond* という名前のマクロを書いて使ってます。ただこれを他の人もいじるコードでも使うべきかはかなり悩むところ

2015-06-22T10:13:43.000556Z

(他にも let1 とか、scheme(gauche)由来のマクロが結構あります)

2015-06-22T10:16:03.000557Z

ちょっとテスト
これでいいのかな

2015-06-22T10:16:54.000558Z

;;; (cond*
;;;   [(very-long-pred? arg1 arg2 arg3)
;;;    (very-long-proc! arg4 arg5 arg6)]
;;;   [(pred2?) =&gt; #(proc2 arg1 arg2 % arg3)]
;;;   [(pred3?) (do-aaa!) (do-bbb!) (do-ccc!)]
;;;   [:else (proc3! arg1 arg2 arg3)])
(defmacro cond*
  "cond came from scheme"
  [&amp; clauses]
  ;; clausesが空の場合はnil(再帰展開時用。ifの第二引数が省略可能なのを利用)
  (if (empty? clauses)
    nil
    (let [current-clause (first clauses)
          left-clauses (rest clauses)
          pred (first current-clause)
          bodies (rest current-clause)
          body-fn (when (= '=&gt; (first bodies))
                    (second bodies))]
      (cond
        ;; =&gt; がある場合は、predの結果をbodyに適用(優先順位高)
        body-fn `(if-let [r# ~pred]
                   (~body-fn r#)
                   (cond* ~@left-clauses))
        ;; 'else もしくは :else の時はショートカット可能
        ;; TODO: 数値等の、他の真値にも対応してもよい
        (or
          (= 'else pred)
          (keyword? pred)) `(do ~@bodies)
        ;; それ以外の場合は普通にifに展開
        :else `(if ~pred
                 (do ~@bodies)
                 (cond* ~@left-clauses))))))

2015-06-22T10:17:13.000559Z

こんなの

2015-06-22T10:32:50.000560Z

これまた話が戻るんですが、自分は :pre を使わずに、関数の最初の方で (assert ...) を書くようにしてます。理由は :pre だと例えば、 (defn foo [m] {:pre [(map? m)]} (do-something)) で m がmapじゃなかった時に「じゃあmには何が入っていたのよ?」というのを表示してくれないから…

2015-06-22T10:33:54.000561Z

とは言え (assert (map? m)) でもそれは同様なので、いちいち (assert (map? m) (str "Invalid map " m)) みたいに毎回書く事が多いです。

2015-06-22T10:34:41.000562Z

この辺、便利機能が実は既にあったりしないでしょうか…

ayato_p 2015-06-22T10:36:08.000563Z

アサートの話だと個人的にそれはテストで解決できる気がするんですが、それじゃダメなんでしょうか?

2015-06-22T10:38:05.000564Z

あー、なるほどです、テストを通すなら、テスト側で渡してる値が分かってるからokですね。自分はあまりテスト書かないので…

ayato_p 2015-06-22T10:44:31.000565Z

アサーションは「この関数にはこういうものを期待してます」という表明なので、そこにそれ以外のものが来る場合は呼び出し側の実装が悪いはずで、そっち側を僕なら調べるかなぁと。

ayato_p 2015-06-22T10:44:56.000566Z

あと、そういうときは spyscope とか使うと楽ですかねー。

2015-06-22T10:46:14.000567Z

おー、こんなのあるんですね > spyscope

2015-06-22T10:46:28.000568Z

https://github.com/dgrnbrg/spyscope

ayato_p 2015-06-22T10:53:09.000570Z

僕が clojure 始めたときに教えてもらって結構重宝してました。(最近そういえばあまり使ってない気がしますが

icalo35 2015-06-22T12:05:32.000571Z

おっ、丁度こんな感じの欲しいと思ってたのです。早速導入しよう。

icalo35 2015-06-22T12:07:11.000572Z

なんかこう、1つの関数がズントコでかくなっていって、途中の動きがわからず混乱する事が多いのです。

ayato_p 2015-06-22T12:19:39.000573Z

僕が書いたやつであれですけど、デバッグ周りで悩んでるならこの辺参考になると思いますー。 http://ayato.hateblo.jp/entry/20150419/1429437366 ついでに言うと Cursive ならステップ実行とか普通に出来て便利でした。

icalo35 2015-06-22T12:43:52.000575Z

わー、ドンピシャなテクやたらあるー! ありがとうございます!

icalo35 2015-06-22T12:44:35.000576Z

なんというか「あとがき」に共感することしきり。

icalo35 2015-06-22T12:47:17.000577Z

というか暇なときにあやぴーさんのブログ全体的に読み漁った方が色々良い気がしてきた。ググって見付けて参考にした事は何度もあるのですが。

ayato_p 2015-06-22T13:13:15.000578Z

(全体的に読み漁られると闇しかないです…)

2015-06-22T13:31:59.000579Z

ここしばらく、cljsでゲームを作っていました。 http://vnctst.tir.jp/ja/games/op0012-3.html

ayato_p 2015-06-22T13:40:03.000580Z

オープニングがシュールで笑いましたw でも、凄いですね。こういうゲームとか作ったこと無いので作ってみたいです :simple_smile:

icalo35 2015-06-22T14:07:08.000581Z

あばばば…cljsというか、js環境でこんだけ出来るんですか……しゅごい……

icalo35 2015-06-22T14:07:35.000582Z

(非推奨とされているスマホプレしつつ)

icalo35 2015-06-22T14:08:21.000583Z

canvasとかで昔のスーファミとかの疑似3Dやってるんですよねこれ。

2015-06-22T23:26:48.000584Z

はい。きちんと3Dの処理はしてないです。canvasを使ってます