« タスクバーで目的のショートカットを選ぶまでの時間を短縮 |Main| Haskell日記 »

« タスクバーで目的のショートカットを選ぶまでの時間を短縮 | zakki(雑記) | Haskell日記 »

Tomcatハック日記2 JSPの章

JSPに初挑戦。 見よう見まねでとりあえずJythonが動くようにしてみた。
<%@ page
    contentType="text/html; charset=Shift_JIS"
    session = "false"
    import = "org.python.util.PythonInterpreter"
%>
<html>
<body>
<pre>
<%
  PythonInterpreter pyi = new PythonInterpreter();
  String code = request.getParameter("code");
  pyi.set("out", out);
  pyi.exec("import sys; old_out = sys.stdout; sys.stdout = out");
  if(code == null){
    code = "";
  }
  pyi.exec(code);
  pyi.exec("sys.stdout = old_out");
%>
</pre>
<form method="post" action="test.jsp">
  <textarea name="code" cols=80 rows=10><%= code %></textarea><br>
  <input type="submit">
</form>
</body>
</html>
テキストエリアに「print "hoge" * 3」とか書いてsubmitボタンを押すと、 ちゃんと「hogehogehoge」と表示される。 でもこれだとPythonインタプリタが毎回死んでしまう。 どうしたらいいのかな。

とりあえずsession.setAttributeして使い回すようにしてみた。 セッションが続いている間は同じインタプリタを使うようにした。 import osしたら、os.listdirでローカルのファイル一覧が見える。 特にセキュリティ上の制約とかはないみたいだ。

「print session.getValueNames()」で 「array(['pyi', 'hoge'], java.lang.String)」と表示された。 「session.setAttribute("hoge", 2)」で問題なく書き換えられた。

とりあえずsessionの中身を自由に書き換えられるようにはなった。

アプリケーションスコープの変数を使えば 他のセッションとPythonインタプリタを共有できそうだ。 Firefoxの画面で「x = 1」を実行してから、IEを起動して「print x」とやったら、 無事「1」と表示された。

あとは何ができるとうれしいんだろう。 見かけを対話型インタプリタに近づけるのは、技術的には難しくないと思うしな。 チャット風に。

<%@ page
    contentType="text/html; charset=Shift_JIS"
    import = "org.python.util.PythonInterpreter"
%>
<html>
<body>
<textarea cols=80 rows=10>
<%
  PythonInterpreter pyi = (PythonInterpreter)application.getAttribute("pyi");
  if(pyi == null){
    pyi = new PythonInterpreter();
    application.setAttribute("pyi", pyi);
  }
  String code = request.getParameter("code");
  pyi.set("session", session);
  pyi.set("out", out);
  pyi.exec("import sys; old_out = sys.stdout; sys.stdout = out");
  if(code == null){
    code = "";
  }
  pyi.exec(code);
  pyi.exec("sys.stdout = old_out");
%>
</textarea>
<form method="post" action="test.jsp">
  <textarea name="code" cols=80 rows=10><%= code %></textarea><br>
  <input type="submit">
</form>
</body>
</html>

= 雨蛙散乱前線。
= JythonインタプリタからJyConsoleを起動する。 昨日JythonインタプリタからTomcatを起動したのと同じ方法で起動まではうまく行く。 でも、Jythonインタプリタ側の入出力が動かなくなる。

よく考えたら普通にJavaプログラムでJyConsoleを立ち上げた上で、 そのJyConsoleの持っているPythonインタプリタに、 そのPythonインタプリタへの参照をつっこんでやればいい。 自分自身を動的に書き換えられるインタプリタになる。

package org.nishiohirokazu.jythonbook.test;

import javax.swing.JFrame;

import com.artenum.jyconsole.JyConsole;
import com.artenum.jyconsole.python.JInteractiveInterpreter;

public class Ouroboros {
	public static void main(String[] args) {
		System.setProperty("python.security.respectJavaAccessibility", "false");
		JyConsole jyc = new JyConsole();
		JInteractiveInterpreter pyi = jyc.getPythonInterpreter();
		pyi.set("pyi", pyi);
		
		JFrame f = new JFrame();
		f.setSize(500, 300);
		f.add(jyc);
		f.setVisible(true);
	}
}

= 今日は研究室の今年度最後の意見交換会。 ある種の忘年会。忘年度会。

そんなわけでまとまった執筆はできないと踏んでいたので色々試してみた↑

あととりあえずGHC(Haskell)をインストールしてみた。 missingPyを試したい。

ghci(対話的インタプリタ)で関数が定義できないって、ひどい。

HelloWorldできた。 mainという変数の値はアクションというものらしい。 ふむふむ。 たぶん純粋な関数のことだけを関数と呼んで、 副作用のある関数はアクションと呼ぶんだろう。

main = do x <- "Hello. world"
          putStrLn x
怒られた。
main = putStrLn x where x = "Hello. world"
こうか。
main = let x = "Hello. world"
       in putStrLn x
これもOK。

関数適用は f arg1 arg2 arg3で Java風にいうとf(arg1, arg2, arg3)になるわけだけど、 これって部分適用があるから f(arg1)(arg2)(arg3)なんだよね?

Lispと比べて括弧が少ないけど、 その代わりに$があるよ!

階乗。

main = print $ facto 5

facto :: Int -> Int
facto 1 = 1
facto n = n * facto (n - 1)
パターンマッチで関数を定義するところがPrologっぽくて面白い。 あと、最初「main = print facto 5」と書いて怒られた。 factoにprintを適用してしまうんだな、きっと。 関数適用が左結合性ということ? 「facto (n - 1)」も最初 「facto n - 1」と書いて、スタックオーバーフロー。 「facto(n) - 1」と認識されたんだろう。

LispやSchemeと違って括弧が省略できて楽だけど、 その分、どこがどう結合するのかは意識する必要がありそう。

「facto $ n - 1」にすると怒られる。 たぶん n を関数だと思ったんだろう。 「facto & - n 1」にしても怒られる。 たぶん - は関数ではないんだろう。

あ、違う。 「facto $ n - 1」にすると怒られるのは 「(n * facto) $ (n - 1)」と解釈されて、 IntのnとInt->Intのfactoの掛け算が定義されていないからだ。

facto n = (\x -> n * x) $ facto $ n - 1

これならちゃんと動く。括弧なしで書こうと思ったんだけど、とっちゃうとダメ。

carがheadでcdrがtail。


=
main = print  $ minMap [3, 2, 5, 1]

minMap :: [Int] -> Int
minMap [x] = x
minMap (x:xs) = min x $ minMap xs
ふむふむ。
= 100までの素数。
main = print  $ filter isPrime [2..100]

isPrime :: Int -> Bool
isPrime x = not $ any (\n -> n == 0) $ map (mod x) [2..x-1]
簡単。「(\n -> n == 0)」はなんかいい書き方ないのかなあ。
= ガードを使ってみた。Collatzの数列。
main = print  $ collatzList 7

collatz :: Int -> Int
collatz x | mod x 2 == 0 = div x 2
          | otherwise    = x * 3 + 1

collatzList :: Int -> [Int]
collatzList 1 = [1]
collatzList n = n: (collatzList $ collatz n)
「n: $ collatzList $ collatz n」ってやったら怒られた。
= 三段論法(笑)
main = print  $ die "socrates"

die x | human x = True
      | otherwise = "unknown"

human "socrates" = True

= おお、演算子をかっこで囲うと前置にできるんだそうな。 100までの素数を求めるコードはこうなる。
main = print  $ filter isPrime [2..100]

isPrime :: Int -> Bool
isPrime x = all ((<) 0) $ map (mod x) [2..x-1]
たぶん関数の合成を使うともっとスマートに書けるんだろう。
=
main = print $ filter (\x -> all (((<) 0).(mod x)) [2..x-1]) [2..100]
あんまりスマートではない。
= 二項演算子に部分適用を使う場合、(0 <)とか(< 0)とか書けるそうな。
main = print $ filter (\x -> all ((0 <).(mod x)) [2..x-1]) [2..100]
!=は/=らしい。
= Haskellでは関数適用が一番優先順位が高い。ひどい。 一般的な言語ではf(arg1, arg2, arg3)と関数を呼ぶ際に、 fとarg1の間のかっこや、arg1とarg2の間のカンマは最も優先度の低い演算子の役割をする。 でもHaskellの場合はf arg1 arg2 arg3の間の空白文字が一番優先度の高い演算子。見えないくせに。

というわけで(mod x)の周りのかっこはとりのぞける。

main = print $ filter (\x -> all ((0 <).mod x) [2..x-1]) [2..100]

= そんなわけで「ふつうのHaskell」を220ページまで読んだわけだけど、 いよいよ型と型クラス。どきどき。

モナド。どきどき。

モナドって、例えばリストに対して追加を行う関数appendは、適用する順番が大事だから、

append (append (append [] 1) 2) 3
というように書かないといけないところを、
(bind (bind (return 1) append 2) append 3)
と書けるようにbindとreturnを定義して、 bindを二項演算子に変えて
(((return 1) >>= append 2) >>= append 3)
余計なかっこを取り除いて
return 1 >>= append 2 >>= append 3
とした、というだけ?
= 自分でモナドを定義してみようとしたのだけど
    No instance for (Show (m t))
      arising from use of `print' at test.hs:1:7-11
    Possible fix: add an instance declaration for (Show (m t))
    In the first argument of `($)', namely `print'
    In the expression: print $ (return 1)
    In the definition of `main': main = print $ (return 1)
printがないって怒られる。 もう寝よう。
=
instance Show MyMonad where
  show (MyMonad x) = show(x)
こんどはkind mis-matchといわれるようになった。

トラックバック(Trackback)

Trackback URL: http://www.nishiohirokazu.org/mt/mt-tb.cgi/530

フィードバック

by Yusuke.m | 2007年03月13日 22:35

出来るかなー漠然と思ってたことが、本当に出来るんですね。Jythonすごい。

by れり | 2007年03月16日 23:57

もうわかってるかもしれないがコメント
>関数適用は f arg1 arg2 arg3で Java風にいうとf(arg1, arg2, arg3)になるわけだけど、これって部分適用があるから f(arg1)(arg2)(arg3)なんだよね?

カリー化関数だから,
(((f arg1) arg2) arg3)だよね

>一般的な言語ではf(arg1, arg2, arg3)と関数を呼ぶ際に、 fとarg1の間のかっこや、arg1とarg2の間のカンマは最も優先度の低い演算子の役割をする。

関数呼出しに()と,をくっつけるかそうでないかの違いだからしょうがない.つか,関数適用((f arg1) arg2) ...の()を省略してもいいよっていう規則なだけなんだけど.わかりにくければ()を常につければいい.

いや、省略できるのはいいんだけど、 f.g xが((f.g) x)じゃなくて(f . (g x))なのは気持ちが悪くない?

by れり | 2007年03月18日 00:52

あー,たしかに関数適用が他の演算子より優先度が高いと,そういうところで気持ち悪いね・・・.納得です.

ご意見・ご感想をお送りください(フィードバック)

(フィードバックはメールで送信され、基本的に表示されませんが、内容によっては公開させていただくこともございます。ご了承ください。Your comment doesn't appear the page immediately. If the comment has value to other people, it will be put on the page or subsequent entries. Thank you.)

上の情報は、いずれも未記入でかまいません。 All of above questions are optional.