トランザクション内で、リファレンスの値の変更に失敗した場合は、トランザクションの最初から処理をリトライする。
トランザクションの処理に時間がかかり、何回繰り返してもリファレンスの値を更新できない場合は Live lock 状態になる。Clojureでは、これを防ぐため、リトライ回数がある一定値を越えると、例外を投げる仕組みになっている。
リトライ回数の最大値はどのくらいかなと、調べてみた。
(def x (ref 0))
(defn test1 []
(dosync
@(future (dosync (alter x inc)))
(ref-set x -1)))
user> (test1)
RuntimeException Transaction failed after reaching retry limit clojure.lang.Util.runtimeException (Util.java:219)
user> x
#<Ref@843d62: 10000>
user>
最大10000回もリトライしていた。
数十回程度かなと思っていたので、少しびっくり。
この値は変更できるのか、ざっと調べてみたが、変更方法は見付からなかった。
Clojure の STM のドキュメントのどこかに書いてあるのかな?
2013年12月12日木曜日
2013年12月7日土曜日
[Clojure]形態素解析ライブラリKuromojiを使う
オーム社の100周年記念セールで、はじめてのAIプログラミング C言語で作る人工知能と人工無能を購入した。2006年に出版された書籍で、C言語(Borland C)での実装が解説してある。
この類のプログラムをCで実装するのは煩雑になってしまうので、Clojureで作ったらどんなふうになるのかなと思い、文字列の解析時に使用する形態素ライブラリを調べてみた。
Lucene や Solr に対応したlucene-gosen が、結構使われているようだけど、mavenリポジトリにあるバージョンは少し古く、また、多くのライブラリに依存していており、それらのラブラリのバージョンも少し古かった。
その点、Kuromojiは、依存ライブラリがなく、lucene-gosenと同様に辞書も同梱されているので、こちらのライブラリを試してみた。
project.cljに次の設定を書く。
:repositories [["Atilika Open Source repository"
"http://www.atilika.org/nexus/content/repositories/atilika"]]
:dependencies [[[org.atilika.kuromoji/kuromoji "0.7.7"]]
リポジトリのURLの追加方法が最初分からず、いろいろ調べたが、
sample.project.cljのサンプルが参考になった。
(:import (org.atilika.kuromoji Token Tokenizer)))
(defn -main []
(let [tokenizer (. (Tokenizer/builder) build)]
(doseq [token (. tokenizer tokenize "Javaより楽しいClojure。")]
(println (str (. token getSurfaceForm) "\t"
(. token getAllFeatures))))))
何のことはない。Kuromojiのクラスを使う単純なコードだ。
gosen.core> (-main)
Java 名詞,固有名詞,組織,*,*,*,*
より 助詞,格助詞,一般,*,*,*,より,ヨリ,ヨリ
楽しい 形容詞,自立,*,*,形容詞・イ段,基本形,楽しい,タノシイ,タノシイ
Clojure 名詞,一般,*,*,*,*,*
。 記号,句点,*,*,*,*,。,。,。
nil
ユーザ辞書を追加することも簡単なようなので、試してみる予定。
この類のプログラムをCで実装するのは煩雑になってしまうので、Clojureで作ったらどんなふうになるのかなと思い、文字列の解析時に使用する形態素ライブラリを調べてみた。
Lucene や Solr に対応したlucene-gosen が、結構使われているようだけど、mavenリポジトリにあるバージョンは少し古く、また、多くのライブラリに依存していており、それらのラブラリのバージョンも少し古かった。
その点、Kuromojiは、依存ライブラリがなく、lucene-gosenと同様に辞書も同梱されているので、こちらのライブラリを試してみた。
project.cljにKuromojiの設定を追加
Kuromojiをmavenで使うためには、リポジトリの追加が必要である。project.cljに次の設定を書く。
:repositories [["Atilika Open Source repository"
"http://www.atilika.org/nexus/content/repositories/atilika"]]
:dependencies [[[org.atilika.kuromoji/kuromoji "0.7.7"]]
リポジトリのURLの追加方法が最初分からず、いろいろ調べたが、
sample.project.cljのサンプルが参考になった。
サンプルコード
(ns gosen.core(:import (org.atilika.kuromoji Token Tokenizer)))
(defn -main []
(let [tokenizer (. (Tokenizer/builder) build)]
(doseq [token (. tokenizer tokenize "Javaより楽しいClojure。")]
(println (str (. token getSurfaceForm) "\t"
(. token getAllFeatures))))))
何のことはない。Kuromojiのクラスを使う単純なコードだ。
実行結果
replより実行した。gosen.core> (-main)
Java 名詞,固有名詞,組織,*,*,*,*
より 助詞,格助詞,一般,*,*,*,より,ヨリ,ヨリ
楽しい 形容詞,自立,*,*,形容詞・イ段,基本形,楽しい,タノシイ,タノシイ
Clojure 名詞,一般,*,*,*,*,*
。 記号,句点,*,*,*,*,。,。,。
nil
ユーザ辞書を追加することも簡単なようなので、試してみる予定。
参考
Java製形態素解析器「Kuromoji」を試してみる2013年12月2日月曜日
[Clojure][Emacs]Clojure Cheatsheet for Emacs
EmacsでClojureのCheatsheetを閲覧できるELispがあった。
Clojure Cheatsheet for Emacs
試しに使ってみたら、結構便利。
Emacs初期化ファイルに以下のような設定を書いておけば良い。
;; MELPAを有効にする
(add-to-list 'package-archives '("melpa" . "http://melpa.milkbox.net/packages/") t)
サイトの説明通り、以下のコマンドでインストールする。
M-x package-refresh-contents
M-x package-install RET clojure-cheatsheet
ミニバッファに
pattern:
と表示されるので、検索したい文字列を入力する。
sort mapを入力した場合は、次のように表示される。
キーバインドは次の通り。
C-p 前の行
C-n 次の行
RET 選択した項目の表示
clojure-mode時に有効になるような、キーバインドを書いておくと便利かも。
試していないが、Helmのsourceにも対応している。
Clojure Cheatsheet for Emacs
試しに使ってみたら、結構便利。
インストール
Emacs24なら、MELPA経由で簡単にインストールできる。Emacs初期化ファイルに以下のような設定を書いておけば良い。
;; MELPAを有効にする
(add-to-list 'package-archives '("melpa" . "http://melpa.milkbox.net/packages/") t)
サイトの説明通り、以下のコマンドでインストールする。
M-x package-refresh-contents
M-x package-install RET clojure-cheatsheet
実行
M-x clojure-cheatsheet を実行すると、ミニバッファに
pattern:
と表示されるので、検索したい文字列を入力する。
sort mapを入力した場合は、次のように表示される。
キーバインドは次の通り。
C-p 前の行
C-n 次の行
RET 選択した項目の表示
clojure-mode時に有効になるような、キーバインドを書いておくと便利かも。
試していないが、Helmのsourceにも対応している。
2013年12月1日日曜日
[Haskell][Clojure]逆ポーランド記法の解析処理
Learn You a Haskell for Great Good で書かれていた逆ポーランド記法の解析処理をClojureで書いてみた。
四則演算のみサポートする単純な処理である。
solveRPN :: String -> Double
solveRPN = head . foldl func [] . words
where
func (x:y:ys) "+" = (y + x) : ys
func (x:y:ys) "-" = (y - x) : ys
func (x:y:ys) "*" = (y * x) : ys
func (x:y:ys) "/" = (y / x) : ys
func xs num = read num : xs
*RPN> solveRPN "1 2 + 3 * 1 - 2 /"
4.0
whereを使うとコードが分かり易くて、なかなか良いね。
(:use [clojure.string :only (split)]))
(defn words [s]
(split s #"\s+"))
(defn op2 [[x y & ys] f]
(conj ys (apply f [y x])))
(defn operate [stack item]
(case item
"+" (op2 stack +)
"-" (op2 stack -)
"*" (op2 stack *)
"/" (op2 stack /)
(conj stack (Double/parseDouble item))))
(defn solve-rpn [exprs]
(first (reduce operate '() (words exprs))))
rpn.core> (solve-rpn "1 2 + 3 * 1 - 2 /")
4.0
solve-rpn関数の中でoperate関数を定義することも可能だが、かえって分かり難くなりそうなので、外出しして関数定義した。
Haskellに比べると冗長になってしまった。
もっと、すっきり書けるのかな?
文字列のdouble型への変換 (Double/parseDouble item) は美しくない。→と思ったときは parse-double関数を作れば良いのだけど。
四則演算のみサポートする単純な処理である。
Haskellの場合
module RPN wheresolveRPN :: String -> Double
solveRPN = head . foldl func [] . words
where
func (x:y:ys) "+" = (y + x) : ys
func (x:y:ys) "-" = (y - x) : ys
func (x:y:ys) "*" = (y * x) : ys
func (x:y:ys) "/" = (y / x) : ys
func xs num = read num : xs
*RPN> solveRPN "1 2 + 3 * 1 - 2 /"
4.0
whereを使うとコードが分かり易くて、なかなか良いね。
Clojureの場合
(ns rpn.core(:use [clojure.string :only (split)]))
(defn words [s]
(split s #"\s+"))
(defn op2 [[x y & ys] f]
(conj ys (apply f [y x])))
(defn operate [stack item]
(case item
"+" (op2 stack +)
"-" (op2 stack -)
"*" (op2 stack *)
"/" (op2 stack /)
(conj stack (Double/parseDouble item))))
(defn solve-rpn [exprs]
(first (reduce operate '() (words exprs))))
rpn.core> (solve-rpn "1 2 + 3 * 1 - 2 /")
4.0
solve-rpn関数の中でoperate関数を定義することも可能だが、かえって分かり難くなりそうなので、外出しして関数定義した。
Haskellに比べると冗長になってしまった。
もっと、すっきり書けるのかな?
文字列のdouble型への変換 (Double/parseDouble item) は美しくない。→と思ったときは parse-double関数を作れば良いのだけど。
2013年11月30日土曜日
[Debian][Haskell]WheezyにHaskell Platform最新版をインストール
Wheezyのghcは少しバージョンが古く、ghc-modをcabal installしたらエラーとなった。
どうしようもなかったので、Haskell Platformの最新版をインストールした。
$ sudo apt-get install freeglut3-dev libgmp10-dev
このままだと、ghcのconfigure時に
checking for path to top of build tree... utils/ghc-pwd/dist/build/tmp/ghc-pwd: error while loading shared libraries: libgmp.so.3: cannot open shared object file: No such file or directory
と怒られるので、シンボリックリンクを張る。
$ sudo ln -s /usr/lib/i386-linux-gnu/libgmp.so.10 /usr/lib/libgmp.so.3
http://www.haskell.org/ghc/download_ghc_7_6_3
より、32bit版をダウンロードする。
(私はWheezy 32bit版を使用している。)
http://www.haskell.org/ghc/dist/7.6.3/ghc-7.6.3-i386-unknown-linux.tar.bz2
展開して/usr/localにインストールする。
$ tar jxf ghc-7.6.3-i386-unknown-linux.tar.bz2
$ cd ghc-7.6.3
$ ./configure
$ sudo make install
http://www.haskell.org/platform/download/2013.2.0.0/haskell-platform-2013.2.0.0.tar.gz
より、ソースをダウンロードする。
ghcと同様に、展開して/usr/localにインストールする。
$ tar zxf haskell-platform-2013.2.0.0.tar.gz
$ cd haskell-platform-2013.2.0.0
$ ./configure
$ make
コンパイルにはしばらく時間がかかる。
$ sudo make install
$ cabal update
$ cabal install ghc-mod
で、ghc-modがインストールできた。
どうしようもなかったので、Haskell Platformの最新版をインストールした。
依存ライブラリのインストール
次のパッケージをapt-get installしておく。$ sudo apt-get install freeglut3-dev libgmp10-dev
このままだと、ghcのconfigure時に
checking for path to top of build tree... utils/ghc-pwd/dist/build/tmp/ghc-pwd: error while loading shared libraries: libgmp.so.3: cannot open shared object file: No such file or directory
と怒られるので、シンボリックリンクを張る。
$ sudo ln -s /usr/lib/i386-linux-gnu/libgmp.so.10 /usr/lib/libgmp.so.3
ghcのインストール
バイナリパッケージを使う。http://www.haskell.org/ghc/download_ghc_7_6_3
より、32bit版をダウンロードする。
(私はWheezy 32bit版を使用している。)
http://www.haskell.org/ghc/dist/7.6.3/ghc-7.6.3-i386-unknown-linux.tar.bz2
展開して/usr/localにインストールする。
$ tar jxf ghc-7.6.3-i386-unknown-linux.tar.bz2
$ cd ghc-7.6.3
$ ./configure
$ sudo make install
Haskell platformのインストール
http://www.haskell.org/platform/linux.htmlhttp://www.haskell.org/platform/download/2013.2.0.0/haskell-platform-2013.2.0.0.tar.gz
より、ソースをダウンロードする。
ghcと同様に、展開して/usr/localにインストールする。
$ tar zxf haskell-platform-2013.2.0.0.tar.gz
$ cd haskell-platform-2013.2.0.0
$ ./configure
$ make
コンパイルにはしばらく時間がかかる。
$ sudo make install
ghc-modのインストール
これで、$ cabal update
$ cabal install ghc-mod
で、ghc-modがインストールできた。
2013年10月9日水曜日
[Clojure][Emacs] Windows環境のnreplで表示される^Mを消す
Windows環境でnreplを使うと、改行文字の^Mが表示されてしまい、とても目障りだ。
user> (dotimes [i 5] (println (str "hello" i)))
hello0^M ←◆これが目障り
hello1^M
hello2^M
hello3^M
hello4^M
nil
user>
Emacs Lispを使いbuffer-display-tableで^Mを表示しないように設定して、対処した。
もっと簡単な方法は無いのかな?
"Do not show ^M in files containing mixed UNIX and DOS line endings."
(interactive)
(setq buffer-display-table (make-display-table))
(aset buffer-display-table ?\^M []))
(add-hook 'nrepl-repl-mode-hook
'remove-dos-eol)
hello0 ← ^M が消えてスッキリ
hello1
hello2
hello3
hello4
nil
user>
user> (dotimes [i 5] (println (str "hello" i)))
hello0^M ←◆これが目障り
hello1^M
hello2^M
hello3^M
hello4^M
nil
user>
Emacs Lispを使いbuffer-display-tableで^Mを表示しないように設定して、対処した。
もっと簡単な方法は無いのかな?
^Mを消すためのEmacs Lisp
(defun remove-dos-eol ()"Do not show ^M in files containing mixed UNIX and DOS line endings."
(interactive)
(setq buffer-display-table (make-display-table))
(aset buffer-display-table ?\^M []))
(add-hook 'nrepl-repl-mode-hook
'remove-dos-eol)
適用後
user> (dotimes [i 5] (println (str "hello" i)))hello0 ← ^M が消えてスッキリ
hello1
hello2
hello3
hello4
nil
user>
参考
2013年10月6日日曜日
[Clojure] clj-webdriverでChromeのUser-Agentを変更する方法(その2)
[Clojure] clj-webdriverでChromeのUser-Agentを変更する方法 でUser-Agentを変更する方法を書いたが、先日、最新のChromeとchromedriverを使ってみると、User-Agentが変更できなくなっていた。
原因を調べてみると、DesiredCapabilitiesオブジェクトにchrome.switchesを追加しても、Chromeの起動オプションに追加されなくなっていた。
起動オプションの追加方法が変更されたようで、ChromeOptions#addArgumentsを使うと問題なく動作した。
従来のダウンロード先にあったドライバは全てdeprecatedになっており、http://code.google.com/p/chromedriver/wiki/WheredAllTheDownloadsGo?tm=2 では、以下の説明があった。
Downloads have been moved to http://chromedriver.storage.googleapis.com/index.html, because Google Code downloads are being deprecated!
[clj-webdriver "0.6.0"]
[org.seleniumhq.selenium/selenium-java "2.35.0"]
(ns clj-webdriver-patch)
(in-ns 'clj-webdriver.core)
(import 'org.openqa.selenium.chrome.ChromeOptions)
(declare new-chrome-driver)
(defn new-driver
"Start a new Driver instance. The `browser-spec` can include `:browser`, `:profile`, and `:cache-spec` keys.
The `:browser` can be one of `:firefox`, `:ie`, `:chrome` or `:htmlunit`.
The `:profile` should be an instance of FirefoxProfile you wish to use.
The `:cache-spec` can contain `:strategy`, `:args`, `:include` and/or `:exclude keys. See documentation on caching for more details."
([browser-spec]
(let [{:keys [browser profile chrome-switches cache-spec]
:or {browser :firefox
profile nil
chrome-switches nil
cache-spec {}}} browser-spec]
(if (= browser :chrome)
(new-chrome-driver chrome-switches)
(init-driver {:webdriver (new-webdriver* {:browser browser
:profile profile})
:cache-spec cache-spec})))))
(defn new-chrome-driver
[chrome-switches]
(let [option (ChromeOptions.)]
;; for Linux
;; (.setBinary option "chrome.binary" "/usr/bin/google-chrome")
(if chrome-switches
(.addArguments option (into-array chrome-switches)))
(init-driver (ChromeDriver. option))))
User-AgentにiPhoneを設定し、googleで「hogehoge」を検索する。
(ns chrometest.core
(:require [clj-webdriver.core])
(:use clj-webdriver-patch)
(:require [clj-webdriver.taxi :as taxi]))
(System/setProperty "webdriver.chrome.driver" "c:/Application/chromedriver/chromedriver-2.4.exe")
(def ^:dynamic *ua-iPhone-3G* "Mozilla/5.0 (iPhone; U; CPU iPhone OS 2_0_1 like Mac OS X; ja-jp) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5B108 Safari/525.20")
(defn user-agent-switch [user-agent]
(str "--user-agent=\"" user-agent "\""))
(defn test1 []
(taxi/set-driver! {:browser :chrome
:chrome-switches [(user-agent-switch *ua-iPhone-3G*)]})
(taxi/to "https://www.google.com/")
(taxi/input-text "input[name='q']" "hogehoge")
(taxi/click "button[name='btnG']"))
原因を調べてみると、DesiredCapabilitiesオブジェクトにchrome.switchesを追加しても、Chromeの起動オプションに追加されなくなっていた。
起動オプションの追加方法が変更されたようで、ChromeOptions#addArgumentsを使うと問題なく動作した。
実行環境
- Windows 8
- clj-webdriver 0.6.0
- chromedriver 2.4
従来のダウンロード先にあったドライバは全てdeprecatedになっており、http://code.google.com/p/chromedriver/wiki/WheredAllTheDownloadsGo?tm=2 では、以下の説明があった。
Downloads have been moved to http://chromedriver.storage.googleapis.com/index.html, because Google Code downloads are being deprecated!
project.clj
次のライブラリをdependenciesに追加した。[clj-webdriver "0.6.0"]
[org.seleniumhq.selenium/selenium-java "2.35.0"]
src/cli_webdriver_patch.clj
前回と同様に、clj-webdriver.coreの関数を再定義して対応する。(ns clj-webdriver-patch)
(in-ns 'clj-webdriver.core)
(import 'org.openqa.selenium.chrome.ChromeOptions)
(declare new-chrome-driver)
(defn new-driver
"Start a new Driver instance. The `browser-spec` can include `:browser`, `:profile`, and `:cache-spec` keys.
The `:browser` can be one of `:firefox`, `:ie`, `:chrome` or `:htmlunit`.
The `:profile` should be an instance of FirefoxProfile you wish to use.
The `:cache-spec` can contain `:strategy`, `:args`, `:include` and/or `:exclude keys. See documentation on caching for more details."
([browser-spec]
(let [{:keys [browser profile chrome-switches cache-spec]
:or {browser :firefox
profile nil
chrome-switches nil
cache-spec {}}} browser-spec]
(if (= browser :chrome)
(new-chrome-driver chrome-switches)
(init-driver {:webdriver (new-webdriver* {:browser browser
:profile profile})
:cache-spec cache-spec})))))
(defn new-chrome-driver
[chrome-switches]
(let [option (ChromeOptions.)]
;; for Linux
;; (.setBinary option "chrome.binary" "/usr/bin/google-chrome")
(if chrome-switches
(.addArguments option (into-array chrome-switches)))
(init-driver (ChromeDriver. option))))
src/chrometest/core.clj
サンプルコード。User-AgentにiPhoneを設定し、googleで「hogehoge」を検索する。
(ns chrometest.core
(:require [clj-webdriver.core])
(:use clj-webdriver-patch)
(:require [clj-webdriver.taxi :as taxi]))
(System/setProperty "webdriver.chrome.driver" "c:/Application/chromedriver/chromedriver-2.4.exe")
(def ^:dynamic *ua-iPhone-3G* "Mozilla/5.0 (iPhone; U; CPU iPhone OS 2_0_1 like Mac OS X; ja-jp) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5B108 Safari/525.20")
(defn user-agent-switch [user-agent]
(str "--user-agent=\"" user-agent "\""))
(defn test1 []
(taxi/set-driver! {:browser :chrome
:chrome-switches [(user-agent-switch *ua-iPhone-3G*)]})
(taxi/to "https://www.google.com/")
(taxi/input-text "input[name='q']" "hogehoge")
(taxi/click "button[name='btnG']"))
Debian Wheezyでの実行
chromedriverの最新版はglibc2.1.15に依存しており、glibcのバージョンを上げなければならない。
How to upgrade glibc from version 2.13 to 2.15 on Debian? にglibcのバージョンを上げる方法が書かれていたが、試していない。
登録:
投稿 (Atom)
